1.问题引入
今天在梳理系统的时,查看系统中的session共享的实现方式,目前主流的session共享采用spring-session 与 redis的解决方案,无奈系统架构还在使用struts2 等老旧的框架,发现原来的session共享的思路与spring-session很是相似,都是通过一个filter过滤器并且自己封装一个request实现HttpServletRequestWrapper ,并重写里面的getSession方法。至于具体实现不多说,由于http 这种无状态的协议,服务端保持会话需要同客户端配合。原理就是
获取session时 会有一个session的标志ID 该id 一般通过写cookie的方式 写入到客户端浏览器中。
tomcat中写cookie的name 一般默认为 JSESSIONID ,写入cookie 后 浏览器中可查看该cookie
会有一个路径 /weixin
然后客户端向服务端发送请求时会携带该cookie信息。
然后服务端根据cookie中的JSESSIONID的值从redis中获取存储的session信息。
那么问题来了
这个路径 /weixin 和 /weixin/ 一样吗
显然不一样
在调试过程中 由于 前面提到的filter 没有拦截一些url 导致,一些请求产生了基于tomcat自己的session,没有从redis中获取。但是查看浏览器发现 JSESSIONID 这个cookie的存储路径 竟然为 /weixin/
然而其他拦截到的url 存的路径为 /weixin (开发人员自己设置的,获取的为contextpath)
也就是开发人员自己设置的 路径与 tomcat 自己设置的路径 不一样。这时调试环境的tomcat版本为8.0.X
我换成了 tomcat8.5.37时 cookie的路径竟然又变回了 /weixin
什么情况这是 。。。。。。。。
2.问题定位
为了一探究竟 我自己查看了 tomcat 设置cookie的路径的地方。
在 ApplicationSessionCookieConfig.java 类中 创建cookie的地方
/**
* Creates a new session cookie for the given session ID
*
* @param context The Context for the web application
* @param sessionId The ID of the session for which the cookie will be
* created
* @param secure Should session cookie be configured as secure
* @return the cookie for the session
*/
public static Cookie createSessionCookie(Context context,
String sessionId, boolean secure) {
SessionCookieConfig scc =
context.getServletContext().getSessionCookieConfig();
// NOTE: The priority order for session cookie configuration is:
// 1. Context level configuration
// 2. Values from SessionCookieConfig
// 3. Defaults
Cookie cookie = new Cookie(
SessionConfig.getSessionCookieName(context), sessionId);
// Just apply the defaults.
cookie.setMaxAge(scc.getMaxAge());
cookie.setComment(scc.getComment());
if (context.getSessionCookieDomain() == null) {
// Avoid possible NPE
if (scc.getDomain() != null) {
cookie.setDomain(scc.getDomain());
}
} else {
cookie.setDomain(context.getSessionCookieDomain());
}
// Always set secure if the request is secure
if (scc.isSecure() || secure) {
cookie.setSecure(true);
}
// Always set httpOnly if the context is configured for that
if (scc.isHttpOnly() || context.getUseHttpOnly()) {
cookie.setHttpOnly(true);
}
cookie.setPath(SessionConfig.getSessionCookiePath(context));
return cookie;
}
发现是从SessionConfig.java 获取的path ,然后继续贴代码
public static String getSessionCookiePath(Context context) {
SessionCookieConfig scc = context.getServletContext().getSessionCookieConfig();
String contextPath = context.getSessionCookiePath();
if (contextPath == null || contextPath.length() == 0) {
contextPath = scc.getPath();
}
if (contextPath == null || contextPath.length() == 0) {
contextPath = context.getEncodedPath();
}
if (context.getSessionCookiePathUsesTrailingSlash()) {
// Handle special case of ROOT context where cookies require a path of
// '/' but the servlet spec uses an empty string
// Also ensure the cookies for a context with a path of /foo don't get
// sent for requests with a path of /foobar
if (!contextPath.endsWith("/")) {
contextPath = contextPath + "/";
}
} else {
// Only handle special case of ROOT context where cookies require a
// path of '/' but the servlet spec uses an empty string
if (contextPath.length() == 0) {
contextPath = "/";
}
}
return contextPath;
}
发现 其根据 SessionCookiePathUsesTrailingSlash 配置 来确定是否在 contextPath 后面加 “/”
难道问题出在 这个属性的设置上?
然后我就查看tomcat的更新日志 果然查到了呢 哈哈哈哈哈哈
https://tomcat.apache.org/tomcat-8.5-doc/changelog.html
在8.5.4的版本中 有更新的说明如下
Change the default of the sessionCookiePathUsesTrailingSlash attribute of the Context element to false since the problems caused when a Servlet is mapped to /* are more significant than the security risk of not enabling this option by default. (markt)
也就是 之前这个属性为 true 之后版本默认值改成了false
所以 cookie的路径 返回 一个 为 /weixin/ 一个为/weixin
至于为什么要修改呢
检索到这么一篇文章
http://tomcat.10.x6.nabble.com/Problems-with-default-for-sessionCookiePathUsesTrailingSlash-td5051868.html
从以上文章中可以学到 cookie 的path的作用呢 。