Как разобрать строку cookie - PullRequest
25 голосов
/ 07 апреля 2011

Я хотел бы взять строку Cookie (как она может быть возвращена в заголовке Set-Cookie) и иметь возможность легко изменять ее части, в частности, дату истечения срока действия.

Я вижу, что есть несколько различных классов Cookie, таких как BasicClientCookie, но я не вижу простого способа разбить строку на один из этих объектов.

Я вижу, на уровне API 9 они добавили HttpCookie , который имеет метод синтаксического анализа, но мне нужно что-то для работы в предыдущих версиях.

Есть идеи?

Спасибо

Ответы [ 8 ]

91 голосов
/ 01 апреля 2013

Как насчет java.net.HttpCookie:

List<HttpCookie> cookies = HttpCookie.parse(header);
11 голосов
/ 07 апреля 2011

Полагаю, вам придется разобрать его вручную.Попробуйте это:

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 отображаются в качестве первого атрибута: я не уверен, обязательно ли это так, но именно так упорядочены все файлы cookie, которые я когда-либо видел.

8 голосов
/ 28 октября 2012

Для этого вы можете использовать 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;
}
7 голосов
/ 26 сентября 2015

Довольно забавно, но класс 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());

Этот оператор сохранит куки в следующем формате:

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

И затем вы захотите восстановить этот куки, так что вы получите строку:

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, которые предназначены для использования многими и многими людьми), и я надеюсь,это будет кому-то полезно.

6 голосов
/ 29 июля 2011

С помощью регулярного выражения, такого как:

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

, вы можете проанализировать файл cookie следующим образом:

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

в нескольких строках кода.

0 голосов
/ 05 апреля 2018

Если у вас установлен HTTP-кодек Netty, вы также можете использовать io.netty.handler.codec.http.cookie.ServerCookieDecoder.LAX|STRICT. Очень удобно.

0 голосов
/ 25 мая 2016
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();
0 голосов
/ 01 апреля 2013

Преимущество подхода Янченко с клиентом 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. Это нужно немного подправить. Без '?' модификатор количества в конце ';' конечный атрибут для любого файла cookie не будет сопоставлен. После этого, если вам небезразличны другие атрибуты, вы можете использовать код Дуга, правильно инкапсулированный, для разбора других групп совпадений.

Редактировать: Также отметьте квалификатор '*' в значении самого файла cookie. Значения являются необязательными, и вы можете получить файлы cookie, такие как "de =", то есть вообще без значений. Глядя на регулярное выражение снова, я не думаю, что он будет обрабатывать атрибуты secure и discard, которые не имеют '='.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...