使用Tiles时Spring会话不在Tomcat 8上工作 - SESSION Cookie未设置,因为已包含响应

时间:2016-07-14 07:33:04

标签: spring tomcat spring-boot tomcat8 spring-session

我在Spring Boot Project上使用Spring Session 1.2.0.RELEASE。这被打包为战争并部署在Tomcat 8上。

我已按照Spring Session文档进行了正确配置。问题是应用程序的入口点是一个控制器,它在会话上设置了一些值,但SESSION cookie没有发送到浏览器。

调试我看到了:

  1. org.springframework.session.web.http.CookieHttpSessionStrategy.onNewSession()尝试编写Cookie:

    this.cookieSerializer .writeCookieValue(new CookieValue(request, response, cookieValue));

  2. org.springframework.session.web.http.DefaultCookieSerializer.writeCookieValue()在响应中设置Cookie:

    response.addCookie(sessionCookie);

  3. 实际上并未编写cookie。底层响应对象是org.apache.catalina.core.ApplicationHttpResponse。它的addCookie()方法是:

    /**
      *  Disallow <code>addCookie()</code> calls on an included response.         
      *  @param cookie The new cookie
      */
    @Override
    public void addCookie(Cookie cookie) {
    
        if (!included)
            ((HttpServletResponse) getResponse()).addCookie(cookie);
    
    }
    
  4. 问题是included属性,在某些时候设置为true,阻止添加cookie。

    当正在为jsp(使用tile)提供服务时会发生这种情况:

    enter image description here

    更新

    这是将响应标记为包含的时刻(当standard.jsp切片布局插入属性时:

    <tiles:insertAttribute name="header" ignore="false"/>

    enter image description here

2 个答案:

答案 0 :(得分:0)

要解决此问题,我最终创建了一个过滤器来强制创建会话。

如图所示,对控制器的第一次调用没有添加cookie,因为在Tiles-JSP渲染期间,响应已被标记为包含。我所做的是强制在过滤器中创建会话并重定向询问同一个requestURI。这样,由于调用不涉及渲染,因此创建cookie并可在下次调用中立即使用。

@Bean
@ConditionalOnExpression("${sessionEnforcerFilter.enabled:true}")
public FilterRegistrationBean sessionEnforcerFilter(){
    logger.info("Registering sessionEnforcerFilter");
    FilterRegistrationBean frb = new FilterRegistrationBean();
    frb.setName("sessionEnforcerFilter");
    frb.setFilter(new SessionEnforcerFilter());
    frb.setUrlPatterns(Arrays.asList(new String[]{"/*"}));
    return frb;
}

public class SessionEnforcerFilter implements Filter{

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {}

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)throws IOException, ServletException {
        HttpServletRequest httpServletRequest = (HttpServletRequest)request;
        HttpServletResponse httpServletResponse = (HttpServletResponse)response;
        if(httpServletRequest.getSession(false)==null){
            logger.debug("sessionEnforcerFilter.doFilter () - Session is null - forcing its creation");
            httpServletRequest.getSession();
            String requestURI = httpServletRequest.getRequestURI();
            logger.debug("sessionEnforcerFilter.doFilter () - Repeating request [{}]", requestURI);
            httpServletResponse.sendRedirect(requestURI);
        }else{
            chain.doFilter(httpServletRequest, response);
        }
    }

    @Override
    public void destroy() {}

}

答案 1 :(得分:0)

<强>摘要

  1. 在SessionRepositoryResponseWrapper.onResponseCommitted()中保留breakPoint。

  2. 检查SessionRepositoryRequestWrapper中的响应对象是否为非包装响应。 (包括=假)

  3. 如果它是一个包装的响应对象,请确保sessionRepositoryFilter是第一个。

  4. =====

    当'DispatcherType.INCLUDE(included = true)'时,Spring-session已经处理了这个问题。

    SessionRepositoryResponseWrapper.onResponseCommitted()正在尝试将addCookie添加到原始响应对象。

    sessionRepositoryFilter必须位于第一个位置,以包装tomcat传递的原始applicationHttpResponse。

    问题情况

    • SessionRepositoryRequestWrapper接收包装的响应并保留它。

    • 在servlet容器中执行doInclude()时,找到原始响应并用ApplicationHttpResponse(included = true)包装它。 然后,SetResponse(新的包装响应)到最里面的包装器。

    http://grepcode.com/file/repo1.maven.org/maven2/org.apache.tomcat.embed/tomcat-embed-core/8.0.24/org/apache/catalina/core/ApplicationDispatcher.java#ApplicationDispatcher.doInclude%28javax.servlet.ServletRequest%2Cjavax.servlet.ServletResponse%29

    http://grepcode.com/file/repo1.maven.org/maven2/org.apache.tomcat.embed/tomcat-embed-core/8.0.24/org/apache/catalina/core/ApplicationDispatcher.java#ApplicationDispatcher.wrapResponse%28org.apache.catalina.core.ApplicationDispatcher.State%29

    • Spring-session对SessionRepositoryResponseWrapper.onResponseCommitted()中存储的响应(期望原始响应)执行addCookie,但它不能,因为它设置为'included = true'。