过期 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、正文)对象