Как разбирать строку cookie
Я хотел бы взять строку Cookie (поскольку она может быть возвращена в заголовке Set-Cookie) и иметь возможность легко изменять ее части, в частности дату истечения срока действия.
Я вижу, что есть несколько разных классов Cookie, таких как BasicClientCookie, доступно, но я не вижу простого способа разбора строки в один из этих объектов.
В api уровне 9 я добавил HttpCookie, который имеет метод parse, но мне нужно что-то работать в предыдущих версиях.
Любые идеи?
Спасибо
Ответы
Ответ 1
Я считаю, что вам придется разобрать его вручную. Попробуйте следующее:
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;
}
Я действительно не компилировал или не запускал этот код, но он должен быть сильным началом. Вероятно, вам придется столкнуться с синтаксическим разбором даты: я не уверен, что формат даты, используемый в файлах cookie, фактически совпадает с DateFormat.FULL
. (Обратите внимание на этот связанный с этим вопрос, который касается обработки формата даты в файлах cookie.) Также обратите внимание, что есть некоторые атрибуты cookie, которые не обрабатываются BasicClientCookie
, например version
и httponly
.
Наконец, этот код предполагает, что имя и значение файла cookie отображаются в качестве первого атрибута: я не уверен, что это обязательно верно, но то, как каждый куки файл, который я когда-либо видел, упорядочен.
Ответ 2
Как насчет java.net.HttpCookie
:
List<HttpCookie> cookies = HttpCookie.parse(header);
Ответ 3
Для этого вы можете использовать средства Apache HttpClient.
Вот выдержка из 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;
}
Ответ 4
Забавно, но класс java.net.HttpCookie
не может анализировать строки cookie с частями домена и/или пути, которые этот точный класс java.net.HttpCookie
преобразовал в строки.
Например:
HttpCookie newCookie = new HttpCookie("cookieName", "cookieValue");
newCookie.setDomain("cookieDomain.com");
newCookie.setPath("/");
Поскольку этот класс не реализует ни Serializable, ни Parcelable, он соблазняет хранить файлы cookie как строки. Итак, вы пишете что-то вроде:
saveMyCookieAsString(newCookie.toString());
Этот оператор сохранит файл cookie в следующем формате:
cookieName="cookieValue";$Path="/";$Domain="cookiedomain.com"
И затем вы хотите восстановить этот файл cookie, так что вы получите строку:
String cookieAsString = restoreMyCookieString();
и попытайтесь разобрать его:
List<HttpCookie> cookiesList = HttpCookie.parse(cookieAsString);
StringBuilder myCookieAsStringNow = new StringBuilder();
for(HttpCookie httpCookie: cookiesList) {
myCookieAsStringNow.append(httpCookie.toString());
}
теперь myCookieAsStringNow.toString();
производит
cookieName=cookieValue
Домены и части пути просто ушли. Причина: метод parse чувствителен к словам таких слов, как "домен" и "путь".
Возможное обходное решение: предоставить другой метод toString(), например:
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();
}
Мне кажется забавным (особенно для таких классов, как java.net.HttpCookie
, которые предназначены для использования многими и многими людьми), и я надеюсь, что это будет полезно для кого-то.
Ответ 5
С регулярным выражением типа:
([^=]+)=([^\;]+);\s?
вы можете разобрать файл cookie следующим образом:
.COOKIEAUTH=5DEF0BF530F749AD46F652BDF31C372526A42FEB9D40162167CB39C4D43FC8AF1C4B6DF0C24ECB1945DFF7952C70FDA1E4AF12C1803F9D089E78348C4B41802279897807F85905D6B6D2D42896BA2A267E9F564814631B4B31EE41A483C886B14B5A1E76FD264FB230E87877CB9A4A2A7BDB0B0101BC2C1AF3A029CC54EE4FBC;
expires=Sat, 30-Jul-2011 01:22:34 GMT;
path=/; HttpOnly
в нескольких строках кода.
Ответ 6
Преимущество подхода Янченко с клиентом Apache Http заключается в том, что он проверяет файлы cookie, соответствующие спецификации на основе источника. Подход с регулярным выражением не сделает этого, но, возможно, вам не нужно.
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;
}
}
Я прикрепил небольшой пример с использованием регулярного выражения yanchenkos. Его нужно немного изменить. Без '?' количественный модификатор на хвосте ';' атрибут trailing для любого cookie не будет сопоставлен. После этого, если вы заботитесь о других атрибутах, вы можете использовать Doug-код, правильно инкапсулированный, для анализа других групп соответствия.
Изменить: Также обратите внимание на классификатор '*' на значение самого файла cookie. Значения являются необязательными, и вы можете получать файлы cookie, такие как "de =", т.е. Никакого значения вообще. Глядя на регулярное выражение снова, я не думаю, что он будет обрабатывать безопасные и отбрасывать атрибуты cookie, у которых нет '='.
Ответ 7
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();
Ответ 8
Если у вас установлен HTTP-кодек Netty, вы также можете использовать io.netty.handler.codec.http.cookie.ServerCookieDecoder.LAX|STRICT
. Очень удобно.
Ответ 9
val headers = ..........
val headerBuilder = Headers.Builder()
headers?.forEach {
val values = it.split(";")
values.forEach { v ->
if (v.contains("=")) {
headerBuilder.add(v.replace("=", ":"))
}
}
}
val headers = headerBuilder.build()