过期 cookie 标头中的字符串

Posted

技术标签:

【中文标题】过期 cookie 标头中的字符串【英文标题】:Expires string in cookie header 【发布时间】:2011-06-04 22:41:25 【问题描述】:

我认为很简单的问题,但我似乎找不到答案。

我正在使用 Cookie 类在 Java Servlet 中编写一个 cookie,该 Cookie 类在响应标头中发送到浏览器,如下所示:

Set-Cookie: test=somevalue; Domain=.mydomain.org; Expires=Thu, 06-Jan-2011 18:45:20 GMT; Path=/

我通过 Servlet 2.5 API 中的 Cookie 类执行此操作。我需要在这个字符串的末尾添加“HTTPOnly”,Servlet 2.5 API 不支持。没问题,我将手动创建字符串并将“HTTPOnly”附加到末尾...

但是,在这样做的过程中,我遇到的挑战是首先在此处设置“Expires”标头,我使用了 .setMaxAge(3600),它创建了该字符串的“Expires”部分。但是,由于我不能使用 Cookie 类,我需要创建“过期”部分的值。

基本上,我怎样才能将“3600”格式化为“Thu, 06-Jan-2011 18:45:20 GMT”?

注意:我可能可以使用 DateFormat 找出正确的模式,但我希望有更好的方法来做到这一点。另一个想法:像以前一样使用 Cookie 类,然后以编程方式将 Cookie 转换为相应的标头字符串,然后将“HTTPOnly”附加到末尾。但是我不知道有什么方法可以获取 Cookie 对象并将其转换为相应的 String 值。

那么可选地,我如何获取一个 Cookie 对象并以编程方式将其转换为相应的字符串值?

谢谢!

【问题讨论】:

【参考方案1】:

类似这样的:

Date expdate = new Date ();
expdate.setTime (expdate.getTime() + (3600 * 1000));
String cookieExpire = "expires=" + expdate.toGMTString();
...

.. 因为 toGMTString() 已被弃用

Date expdate= new Date();
expdate.setTime (expdate.getTime() + (3600 * 1000));
DateFormat df = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz", java.util.Locale.US);
df.setTimeZone(TimeZone.getTimeZone("GMT"));
String cookieExpire = "expires=" + df.format(expdate);

【讨论】:

谢谢,我很确定“toGMTString”方法已被弃用。 我最终使用了稍微不同的模式(请参阅我的答案)来匹配 Servlet 容器生成的内容,我希望找到一种完全避免使用 DateFormat 的方法。但是,这应该可行,并且没有其他答案,所以我将其标记为答案。 格式化日期标题时,使用 java.util.Locale 参数调用 SimpleDateFormat 构造函数很重要,例如,new SimpleDateFormat("dd MMM yyyy kk:mm:ss z", Locale.US) 仅供参考,IE10 似乎拒绝此格式字符串。使用new SimpleDateFormat("EEE, dd-MMM-yyyy HH:mm:ss zzz", Locale.ROOT) 修复它。 cookie 的确切规格是tools.ietf.org/html/rfc6265#section-5.1.1,它出奇地松散。但是,"EEE, dd MMM yyyy HH:mm:ss zzz" 格式(空格而不是连字符)是兼容的,并且也是 HTTP 标头中使用的 HTTP 日期格式 (w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.3.1)。【参考方案2】:

Java 8 现在提供适当的日期格式化程序 DateTimeFormatter.RFC_1123_DATE_TIME:

OffsetDateTime oneHourFromNow 
        = OffsetDateTime.now(ZoneOffset.UTC)
        .plus(Duration.ofHours(1));

String cookieExpires 
        = DateTimeFormatter.RFC_1123_DATE_TIME
        .format(oneHourFromNow);

// E.g. "Tue, 8 Nov 2016 20:15:46 GMT"

此格式对expires 属性有效,请参阅RFC 6265 § 4.1.1,它将格式定义为 RFC 1123 日期:

expires-av        = "Expires=" sane-cookie-date
sane-cookie-date  = <rfc1123-date, defined in [RFC2616], Section 3.3.1>

【讨论】:

很好的答案,并且正确。但我建议使用OffsetDateTime 而不是ZonedDateTime 更清楚您的意图。我们这里只涉及UTC,而不是真正的时区,所以OffsetDateTime 是合适的。真正的时区是与 UTC 的偏移加上一组用于处理诸如夏令时 (DST) 等异常情况的规则。 @BasilBourque,你说得对,OffsetDateTime 在语义上比ZonedDateTime 更正确,我已经进行了相应的编辑。 我们也可以使用 plusDays(x) 其中 x 是整数【参考方案3】:

好吧,我没有看到关于这个问题的太多活动,所以我将尝试回答这个问题,以便为将来寻求答案的任何人提供帮助。不过,我会保持开放状态,让其他人有机会参与进来。

所以我考虑了几个选项......

1)

Apache Commons HTTPClient 项目有一个“DateUtil”类,我希望它可以工作。 http://hc.apache.org/httpclient-3.x/apidocs/org/apache/commons/httpclient/util/DateUtil.html。这提供了方便的方法来将日期格式化为几种标准格式,以便在 http 标头中传达日期……但是,它们似乎都与 servlet 容器返回的内容不完全匹配。

2)

Apache Commons 在该项目中也有一个 Cookie 类,它有一个返回字符串的“toExternalForm”方法。使用它,我想我可能已经能够像往常一样创建cookie,调用“toExternalForm”,然后附加“HTTPOnly”。 http://hc.apache.org/httpclient-3.x/apidocs/org/apache/commons/httpclient/Cookie.html。这可能行得通,但我没有费心去尝试。

3)

我最终决定只使用与我的 Servlet 容器返回的内容相匹配的模式,无论它是否是标准格式。如果这是 Servlet 容器返回的内容,那么它应该可以工作,对吧?为什么不...

SimpleDateFormat COOKIE_EXPIRES_HEADER_FORMAT = new SimpleDateFormat("EEE, dd-MMM-yyyy HH:mm:ss zzz");
COOKIE_EXPIRES_HEADER_FORMAT.setTimeZone(new SimpleTimeZone(0, "GMT"));
Date d = new Date();
d.setTime(d.getTime() + 3600 * 1000); //1 hour
String cookieLifeTime = COOKIE_EXPIRES_HEADER_FORMAT.format(d);
response.setHeader("Set-Cookie", "test=somevalue; Domain=.mydomain.org; Expires=" + cookieLifeTime + "; Path=/; HTTPOnly");

【讨论】:

【参考方案4】:

JasonStoltz 给出的第一个答案是正确的:

1) Apache Commons HTTPClient 项目有一个“DateUtil”类,我希望它可以工作。 http://hc.apache.org/httpclient-3.x/apidocs/org/apache/commons/httpclient/util/DateUtil.html。这提供了方便的方法来将日期格式化为几种标准格式,以便在 http 标头中传达日期……但是,它们似乎都与 servlet 容器返回的内容不完全匹配。

使用 DateTime 库获取未来一小时(或任何时间)的日期对象,然后使用 Apache DateUtil 类。 该类根据 RFC 输出,因此您不必担心它与您的 servlet“通常生成”的内容不匹配 - 浏览器将遵守 RFC

您的代码将如下所示:

// for one hour later (should probably use date libraries in general, this is somewhat awkward)
Date expiresDate = new Date(new Date().getTime() + 3600*1000); 
response.setHeader("Set-Cookie", "Expires=" + DateUtil.formatDate(expiresDate) + ";");

【讨论】:

太棒了。您的代码 sn-p sn-p 设置了“Expires”标头,而不是“Set-Cookie”。

以上是关于过期 cookie 标头中的字符串的主要内容,如果未能解决你的问题,请参考以下文章

使用 http 端点访问 lambda 中的 HTTP 请求(标头、查询字符串、cookie、正文)对象

请求头中cookie和字符串的区别

JavaScript Cookie

springboot-vue前后端分离session过期重新登录的实现

cookie的操作

400 Bad Request - 请求标头或 cookie 太大