http请求中没有set-cookie,却产生了jsessionid;tomcat产生两个sessionid,一个是自定义的sessionid(customSessionId),一个是默认的jsess

背景

项目使用了spring session,并用redis存储,以实现分布式环境下session同步;查看dev tools—>network时发现,有两个sessionid,一个是spring session中指定的customSessionId,一个是tomcat默认的jsessionid,
http请求中没有set-cookie,却产生了jsessionid;tomcat产生两个sessionid,一个是自定义的sessionid(customSessionId),一个是默认的jsess_第1张图片


<bean id="defaultCookieSerializer"
          class="org.springframework.session.web.http.DefaultCookieSerializer">
        <property name="cookieName" value="customSessionId" />
        <property name="cookiePath" value="/" />
bean>

这里我就产生了疑问?明明指定了sessionId为什么还会有默认的jsessionid?既然spring统一管理了session就不会再有新session了呀?!并且在check network中请求后,却发现没有任何请求产生jsessionid,但是application中的的确确产生了jsessionid!

问题

截止到现在产生了两个问题,

  • http请求中没有set-cookie,却产生了jsessionid
  • tomcat产生两个sessionid,一个是自定义的sessionid(customSessionId),一个是默认的jsessionid;

探索

意想不到的source map

为了查清楚第一个问题,使用了排除大法,使用折半删除,最终定位到jquery-migrate-1.1.1.min.js这个文件,如果不引用此文件则没有jsessionid,为了排除js创建jsessionid的可能,搜索文件内容并未发现jsessionid或cookie的代码,这时想到chrome的请求与fiddler的请求不一样让fiddler抓包也许能看到不一样的东西,
http请求中没有set-cookie,却产生了jsessionid;tomcat产生两个sessionid,一个是自定义的sessionid(customSessionId),一个是默认的jsess_第2张图片
果然不一样,凭空多了jquery-migrate.min.map请求且产生了jsessionid,几经搜索,得知这是source map,相当于min.js文件对应的源代码,chrome dev tools默认会下载此文件,至此我们明白了,因为是chrome浏览器本身发送的,所以在network中看不见而fiddler却能抓出来。
当然,我们可以关闭下载source map,

dev tools---->settings--->sources--->enable javascript source maps 去掉勾选

jsp中的session

我们注意到min.map请求响应代码是404,并且产生了jsessionid,没有办法只能跟踪java源代码,追踪到StandardHostValve,执行完invoke方法后,就会产生setCookie,可以排除filter产生jsessionId的可能,再看404.jsp,发现没有指定session=”false”,所以会创建session,在invoke方法这一步等于执行了request.getSession(),因为这时的request已经是原始的request,未经spring包装的request肯定会产生原始的jsessionid,所以有两个sessionid,通过在404.jsp中指定session=”false”就不会再从产生jsessionid;
http请求中没有set-cookie,却产生了jsessionid;tomcat产生两个sessionid,一个是自定义的sessionid(customSessionId),一个是默认的jsess_第3张图片

原理

再回过头来说一下这个事情的原理,
spring session的原理是通过filter,暂且就叫它SpringSessionFilter吧,document要求它必须放在最前边,这样就能保证它会比其他filter先执行,它将tomcat的request、reponse,封装为spring的request、response,从而后边的filter/controller…获取到的request、response都是spring的request、response,这样在controller中request.getSession()肯定是spring制定的springSessionId。

public void doFilter(ServletRequest request, ServletResponse response,
                         FilterChain chain)
            throws IOException, ServletException;

但是StandardHostValve在springsessionfilter的前边执行(看上图的线程栈),所以它获取到的request、response仍然是原始的,所以此时request.getSession()获取到的就是原始的jsessionid。

引出来的段子

由于无法debug tomcat源码,所以standardhostvalve具体功能无从推断,这个还引出tomcat打源代码包的段子

后记

通过这个问题,在跟踪源码阶段,基本了解了spring session原理以及shiro的session原理,filter、filter chain、proxiedfilterchain,跟源码受益无穷呀。

参考

JavaScript Source Map 详解
集成Shiro后当遇到404错误时会丢失session

你可能感兴趣的:(session,cookie,spring)