2011-04-07 32 views
23

Tôi muốn lấy một chuỗi Cookie (vì nó có thể được trả lại trong tiêu đề Set-Cookie) và có thể dễ dàng sửa đổi các phần của nó, cụ thể là ngày hết hạn.Cách phân tích chuỗi cookie

Tôi thấy có một số lớp Cookie khác nhau, chẳng hạn như BasicClientCookie, có sẵn nhưng tôi không thấy bất kỳ cách nào dễ dàng để phân tích cú pháp chuỗi thành một trong các đối tượng đó.

Tôi thấy ở cấp độ api 9 họ đã thêm HttpCookie có phương thức phân tích cú pháp, nhưng tôi cần một cái gì đó để hoạt động trong các phiên bản trước.

Bất kỳ ý tưởng nào?

Cảm ơn

+0

Bạn đang sử dụng ứng dụng khách HTTP nào? Android tàu với Apache Commons HttpClient. – BalusC

+0

Tôi đang sử dụng HttpClient cho các kết nối nhưng tôi đã sử dụng CookieSyncManager để duy trì các cookie. Tôi không sử dụng CookieStore của HttpClient vào lúc này. – cottonBallPaws

Trả lời

10

Tôi tin rằng bạn sẽ phải phân tích cú pháp thủ công. Hãy thử điều này:

BasicClientCookie parseRawCookie(String rawCookie) throws Exception { 
    String[] rawCookieParams = rawCookie.split(";"); 

    String[] rawCookieNameAndValue = rawCookieParams[0].split("="); 
    if (rawCookieNameAndValue.length != 2) { 
     throw new Exception("Invalid cookie: missing name and value."); 
    } 

    String cookieName = rawCookieNameAndValue[0].trim(); 
    String cookieValue = rawCookieNameAndValue[1].trim(); 
    BasicClientCookie cookie = new BasicClientCookie(cookieName, cookieValue); 
    for (int i = 1; i < rawCookieParams.length; i++) { 
     String rawCookieParamNameAndValue[] = rawCookieParams[i].trim().split("="); 

     String paramName = rawCookieParamNameAndValue[0].trim(); 

     if (paramName.equalsIgnoreCase("secure")) { 
      cookie.setSecure(true); 
     } else { 
      if (rawCookieParamNameAndValue.length != 2) { 
       throw new Exception("Invalid cookie: attribute not a flag or missing value."); 
      } 

      String paramValue = rawCookieParamNameAndValue[1].trim(); 

      if (paramName.equalsIgnoreCase("expires")) { 
       Date expiryDate = DateFormat.getDateTimeInstance(DateFormat.FULL) 
         .parse(paramValue); 
       cookie.setExpiryDate(expiryDate); 
      } else if (paramName.equalsIgnoreCase("max-age")) { 
       long maxAge = Long.parseLong(paramValue); 
       Date expiryDate = new Date(System.getCurrentTimeMillis() + maxAge); 
       cookie.setExpiryDate(expiryDate); 
      } else if (paramName.equalsIgnoreCase("domain")) { 
       cookie.setDomain(paramValue); 
      } else if (paramName.equalsIgnoreCase("path")) { 
       cookie.setPath(paramValue); 
      } else if (paramName.equalsIgnoreCase("comment")) { 
       cookie.setPath(paramValue); 
      } else { 
       throw new Exception("Invalid cookie: invalid attribute name."); 
      } 
     } 
    } 

    return cookie; 
} 

Tôi chưa thực sự biên soạn hoặc chạy mã này, nhưng nó phải là khởi đầu mạnh mẽ. Có thể bạn sẽ phải lộn xộn với ngày phân tích cú pháp một chút: Tôi không chắc rằng định dạng ngày được sử dụng trong cookie thực sự giống như DateFormat.FULL. (Hãy xem this câu hỏi liên quan, giải quyết việc xử lý định dạng ngày trong cookie.) Ngoài ra, lưu ý rằng có một số thuộc tính cookie không được xử lý bởi BasicClientCookie chẳng hạn như versionhttponly. Cuối cùng, mã này giả định rằng tên và giá trị của cookie xuất hiện như thuộc tính đầu tiên: Tôi không chắc liệu đó có nhất thiết phải đúng hay không, nhưng đó là cách mọi cookie tôi từng thấy được đặt hàng.

+0

sau nếu (paramName.equalsIgnoreCase ("bình luận")), cookie.setPath (paramValue) có lẽ là sai? –

+1

Tốt hơn để làm những gì @yanchenko đề xuất và sử dụng những gì có trong thư viện gốc. Sử dụng một trong các lớp siêu lớp [CookieSpec] (http://developer.android.com/reference/org/apache/http/cookie/CookieSpec.html) như [BestMatchSpec] (http://developer.android.com/reference/ org/apache/http/impl/cookie/BestMatchSpec.html) –

+1

Điều này sẽ phá vỡ nếu giá trị cookie có ký tự "=" có giá trị –

7

Với một biểu thức chính quy như:

([^=]+)=([^\;]+);\s? 

bạn có thể phân tích một cookie như thế này:

.COOKIEAUTH=5DEF0BF530F749AD46F652BDF31C372526A42FEB9D40162167CB39C4D43FC8AF1C4B6DF0C24ECB1945DFF7952C70FDA1E4AF12C1803F9D089E78348C4B41802279897807F85905D6B6D2D42896BA2A267E9F564814631B4B31EE41A483C886B14B5A1E76FD264FB230E87877CB9A4A2A7BDB0B0101BC2C1AF3A029CC54EE4FBC; 
expires=Sat, 30-Jul-2011 01:22:34 GMT; 
path=/; HttpOnly 

trong một vài dòng mã.

8

Bạn có thể sử dụng các tiện ích của Apache HttpClient cho điều đó.
Dưới đây là một đoạn trích từ CookieJar:

CookieSpec cookieSpec = new BrowserCompatSpec(); 

List<Cookie> parseCookies(URI uri, List<String> cookieHeaders) { 
    ArrayList<Cookie> cookies = new ArrayList<Cookie>(); 
    int port = (uri.getPort() < 0) ? 80 : uri.getPort(); 
    boolean secure = "https".equals(uri.getScheme()); 
    CookieOrigin origin = new CookieOrigin(uri.getHost(), port, 
      uri.getPath(), secure); 
    for (String cookieHeader : cookieHeaders) { 
     BasicHeader header = new BasicHeader(SM.SET_COOKIE, cookieHeader); 
     try { 
      cookies.addAll(cookieSpec.parse(header, origin)); 
     } catch (MalformedCookieException e) { 
      L.d(e); 
     } 
    } 
    return cookies; 
} 
0

Ưu điểm của phương pháp Yanchenko với Apache Http khách hàng là đó là xác nhận các cookie phù hợp với spec dựa trên nguồn gốc. Cách tiếp cận biểu thức chính quy sẽ không làm điều đó, nhưng có lẽ bạn không cần.

public class CookieUtil { 

    public List<Cookie> parseCookieString(String cookies) { 
     List<Cookie> cookieList = new ArrayList<Cookie>(); 
     Pattern cookiePattern = Pattern.compile("([^=]+)=([^\\;]*);?\\s?"); 
     Matcher matcher = cookiePattern.matcher(cookies); 
     while (matcher.find()) { 
      int groupCount = matcher.groupCount(); 
      System.out.println("matched: " + matcher.group(0)); 
      for (int groupIndex = 0; groupIndex <= groupCount; ++groupIndex) { 
       System.out.println("group[" + groupIndex + "]=" + matcher.group(groupIndex)); 
      } 
      String cookieKey = matcher.group(1); 
      String cookieValue = matcher.group(2); 
      Cookie cookie = new BasicClientCookie(cookieKey, cookieValue); 
      cookieList.add(cookie); 
     } 
     return cookieList; 
    } 
} 

Tôi đã đính kèm một ví dụ nhỏ sử dụng yanchenkos regex. Nó cần phải được tinh chỉnh chỉ một chút. Không có '?' modifer số lượng trên dấu ';' thuộc tính trailing cho bất kỳ cookie nào sẽ không được khớp. Sau đó, nếu bạn quan tâm đến các thuộc tính khác, bạn có thể sử dụng mã của Doug, được đóng gói đúng cách, để phân tích các nhóm đối sánh khác.

Chỉnh sửa: Ngoài ra, lưu ý '*' vòng loại trên giá trị của chính cookie đó. Giá trị là tùy chọn và bạn có thể nhận được các cookie như "de =", tức là không có giá trị nào cả. Nhìn vào regex một lần nữa, tôi không nghĩ rằng nó sẽ xử lý các thuộc tính cookie an toàn và loại bỏ mà không có một '='.

77

Làm thế nào về java.net.HttpCookie:

List<HttpCookie> cookies = HttpCookie.parse(header); 
+3

Đây là những gì OP được gọi là không có sẵn cho đến khi api 9. –

+7

@MattWolfe Đúng, nhưng 90% những người tìm thấy câu hỏi này trong năm 2009 không lo lắng về API 9 nữa. Đó là lý do tại sao câu trả lời này đang được upvoted ngay bây giờ. –

+0

phương thức phân tích cú pháp này có vẻ phân biệt chữ hoa chữ thường với các từ như "tên miền" và "đường dẫn", vì vậy bạn nên cẩn thận.Xem câu trả lời chi tiết của tôi –

5

vui đủ, nhưng java.net.HttpCookie lớp không thể phân tích chuỗi cookie với tên miền và/hoặc các bộ phận con đường mà java.net.HttpCookie lớp này chính xác đã chuyển đổi sang chuỗi.

Ví dụ:

HttpCookie newCookie = new HttpCookie("cookieName", "cookieValue"); 
newCookie.setDomain("cookieDomain.com"); 
newCookie.setPath("/"); 

Như lớp này thực hiện không Serializable cũng không Parcelable, nó hấp dẫn để lưu trữ các tập tin cookie như dây đàn. Vì vậy, bạn viết một cái gì đó như:

saveMyCookieAsString(newCookie.toString()); 

Tuyên bố này sẽ tiết kiệm được cookie theo định dạng sau:

cookieName="cookieValue";$Path="/";$Domain="cookiedomain.com" 

Và sau đó bạn muốn khôi phục lại cookie này, vì vậy bạn sẽ có được chuỗi:

String cookieAsString = restoreMyCookieString(); 

và cố gắng phân tích cú pháp:

List<HttpCookie> cookiesList = HttpCookie.parse(cookieAsString); 
StringBuilder myCookieAsStringNow = new StringBuilder(); 
for(HttpCookie httpCookie: cookiesList) { 
    myCookieAsStringNow.append(httpCookie.toString()); 
} 

tại myCookieAsStringNow.toString(); sản xuất

cookieName=cookieValue 

miền và đường dẫn phần chỉ đi. Lý do: phương pháp phân tích cú pháp phân biệt chữ hoa chữ thường với các từ như "tên miền" và "đường dẫn".
thể workaround: cung cấp toString khác() phương pháp như:

public static String httpCookieToString(HttpCookie httpCookie) { 
    StringBuilder result = new StringBuilder() 
      .append(httpCookie.getName()) 
      .append("=") 
      .append("\"") 
      .append(httpCookie.getValue()) 
      .append("\""); 

    if(!TextUtils.isEmpty(httpCookie.getDomain())) { 
     result.append("; domain=") 
       .append(httpCookie.getDomain()); 
    } 
    if(!TextUtils.isEmpty(httpCookie.getPath())){ 
     result.append("; path=") 
       .append(httpCookie.getPath()); 
    } 

    return result.toString(); 
} 

tôi thấy nó buồn cười (đặc biệt là cho các lớp học như java.net.HttpCookie mà là nhằm mục đích để được sử dụng bởi rất nhiều và rất nhiều người) và tôi hy vọng nó sẽ được hữu ích cho ai đó.

+1

Dường như 'HttpCookie' phân tích cú pháp cookie thành cookie máy chủ, nhưng xâu chuỗi chúng thành cookie của người dùng - có lẽ đó là ý định của [JavaDoc] của nó (https://docs.oracle.com/javase/8/docs/api/java/net/HttpCookie.html) đọc: thông tin trạng thái _carries giữa máy chủ và tác nhân người dùng_. Xem thêm [phần ví dụ về RFC 2109] (https://tools.ietf.org/html/rfc2109#section-5). –

0
CookieManager cookieManager = new CookieManager(); 
     CookieHandler.setDefault(cookieManager); 
     HttpCookie cookie = new HttpCookie("lang", "en"); 
     cookie.setDomain("Your URL"); 
     cookie.setPath("/"); 
     cookie.setVersion(0); 

     cookieManager.getCookieStore().add(new URI("https://Your URL/"), cookie); 
     List<HttpCookie> Cookies = cookieManager.getCookieStore().get(new URI("https://Your URL/")); 
     String s = Cookies.get(0).getValue(); 
Các vấn đề liên quan