在实际的开发工作中,需要在多次请求中携带一些带有生命期的数据信息,以及需要和前端协作存储少量含有过期值的必须数据。那么就需要使用到cookie了,有了cookie大家可能会想到,session也可以完成会话时数据的存储呀。他们确实都可以,只是用法,范围以及场景都略有却别!
cookie的过期时间如何设置的呢,很简单掉用setMaxAge(seconds)即可,再通过httpServletResponse.addCookie(cookie)完成cookie的种植即可。虽然只是简单的两步,如果没了解过期值设置的原理,依然后存在问题。cookie在过期时间(自己认为的)内失效,cookie设置的过期值无效,导致获取时不存在。
接下来,通过源码分析如何设置的cookie过期值,又如何在response的headers中设置Set-cookie头。
httpServletResponse作为父接口,所以我们需要看它的子类(子类有很多)
org.apache.catalina.connector.Response#addCookie(cookie)方法:
public void addCookie(final Cookie cookie) {
// Ignore any call from an included servlet
if (included || isCommitted()) {
return;
}
cookies.add(cookie);
String header = generateCookieString(cookie);
//if we reached here, no exception, cookie is valid
// the header name is Set-Cookie for both "old" and v.1 ( RFC2109 )
// RFC2965 is not supported by browsers and the Servlet spec
// asks for 2109.
addHeader("Set-Cookie", header, getContext().getCookieProcessor().getCharset());
}
// 生成cookie字符串。
public String generateCookieString(final Cookie cookie) {
// Web application code can receive a IllegalArgumentException
// from the generateHeader() invocation
if (SecurityUtil.isPackageProtectionEnabled()) {
return AccessController.doPrivileged(new PrivilegedAction<String>() {
@Override
public String run(){
return getContext().getCookieProcessor().generateHeader(cookie);
}
});
} else {
return getContext().getCookieProcessor().generateHeader(cookie);
}
}
这里的getContext().getCookieProcessor()有两个不同的CookieProcessor实现类分别如下:
org.apache.tomcat.util.http.Rfc6265CookieProcessor

org.apache.tomcat.util.http.LegacyCookieProcessor

response中的Set-cookie头是通过CookieProcessor的generateHeader(cookie)实现的,Rfc6265CookieProcessor与LegacyCookieProcessor的实现大致相同。
LegacyCookieProcessor对response中cookie过期值的渲染逻辑如下:

Rfc6265CookieProcessor对response中cookie过期值的渲染逻辑如下:

可以看到,在渲染过期时间时,都有ANCIENT_DATE和COOKIE_DATE_FORMAT属性,其实他们都来自Rfc6265CookieProcessor与LegacyCookieProcessor的基类org.apache.tomcat.util.http.CookieProcessorBase,代码如下:
public abstract class CookieProcessorBase implements CookieProcessor {
private static final String COOKIE_DATE_PATTERN = "EEE, dd-MMM-yyyy HH:mm:ss z";
protected static final ThreadLocal<DateFormat> COOKIE_DATE_FORMAT =
new ThreadLocal<DateFormat>() {
@Override
protected DateFormat initialValue() {
DateFormat df =
new SimpleDateFormat(COOKIE_DATE_PATTERN, Locale.US);
df.setTimeZone(TimeZone.getTimeZone("GMT"));
return df;
}
};
protected static final String ANCIENT_DATE;
static {
ANCIENT_DATE = COOKIE_DATE_FORMAT.get().format(new Date(10000));
}
}
通过TimeZone.getTimeZone(“GMT”),可以看出来,tomcat在处理cookie过期时间时,都是转换为GTM零时区来返回该过期时间的数据,我们则需要依据自己的时区特性,在执行setMaxAge(seconds)时,完成时间的偏移(例如过期时间为5min,那么这里的seconds参数需要设置为5min + 8h,才是东八区(GTM+8)当前时间点之后的5min)。以上便是对cookie过期时间设置的简单摸索。
本文探讨了在Java开发中如何设置Cookie的过期时间,通过分析HttpServletResponse的子类Rfc6265CookieProcessor和LegacyCookieProcessor的实现,揭示了Tomcat在处理Cookie过期时间时会转换为GMT零时区。开发者需要注意根据时区调整setMaxAge(seconds)的参数,以确保正确设置过期时间。
1163

被折叠的 条评论
为什么被折叠?



