繁体   English   中英

如何解析 cookie 字符串

[英]How to parse a cookie string

我想获取一个 Cookie 字符串(因为它可能在 Set-Cookie 标头中返回)并且能够轻松地修改它的部分内容,特别是到期日期。

我看到有几个不同的 Cookie 类可用,例如 BasicClientCookie,但我没有看到任何简单的方法可以将字符串解析为这些对象之一。

我在 api 级别 9 中看到他们添加了具有解析方法的HttpCookie ,但我需要在以前的版本中工作。

有任何想法吗?

谢谢

java.net.HttpCookie怎么样:

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

我相信你必须手动解析它。 试试这个:

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处理,例如versionhttponly

最后,这段代码假设cookie的名称和值显示为第一个属性:我不确定这是否一定是真的,但这就是我见过的每个cookie的订购方式。

您可以使用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;
}

有趣的是,但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

域和路径部分刚刚消失 原因是:解析方法对“域”和“路径”之类的单词区分大小写。
可能的解决方法:提供另一个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这样的课程,它们的目的是被很多人使用)我希望它对某些人有用。

使用正则表达式:

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

你可以像这样解析一个cookie:

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

在几行代码中。

Yanchenko使用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的尾随属性都不匹配。 之后,如果您关心其他属性,可以使用Doug的代码(正确封装)来解析其他匹配组。

编辑:另外,请注意cookie本身值的'*'限定符。 值是可选的,您可以获得像“de =”这样的cookie,即根本没有值。 再看看正则表达式,我认为它不会处理没有'='的安全和丢弃cookie属性。

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();

如果您碰巧安装了Netty HTTP编解码器,您还可以使用io.netty.handler.codec.http.cookie.ServerCookieDecoder.LAX|STRICT 很方便。

如果要解析成javax.servlet.http.Cookie可以先解析成java.net.HttpCookie再转换成Cookie 但理论上它可能因为 cookie 的版本不兼容。

    HttpCookie httpCookie = ...
    Cookie cookie = toServletCookie(httpCookie);
    
    private static boolean isNotEmpty(String str) {
        return !(str == null || str.trim().isEmpty());
    }

    public static Cookie toServletCookie(HttpCookie httpCookie) {
        Cookie cookie = new Cookie(httpCookie.getName(), httpCookie.getValue());
        if (isNotEmpty(httpCookie.getDomain())) {
            cookie.setDomain(httpCookie.getDomain());
        }
        if (isNotEmpty(httpCookie.getPath())) {
            cookie.setPath(httpCookie.getPath());
        }
        cookie.setHttpOnly(httpCookie.isHttpOnly());
        cookie.setSecure(httpCookie.getSecure());
        if (isNotEmpty(httpCookie.getComment())) {
            cookie.setComment(httpCookie.getComment());
        }
        cookie.setMaxAge((int) Math.min(httpCookie.getMaxAge(), Integer.MAX_VALUE));
        return cookie;
    }
        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()

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM