我在Spring Boot Project上使用Spring Session 1.2.0.RELEASE。这被打包为战争并部署在Tomcat 8上。
我已按照Spring Session文档进行了正确配置。问题是应用程序的入口点是一个控制器,它在会话上设置了一些值,但SESSION cookie没有发送到浏览器。
调试我看到了:
org.springframework.session.web.http.CookieHttpSessionStrategy.onNewSession()
尝试编写Cookie:
this.cookieSerializer
.writeCookieValue(new CookieValue(request, response, cookieValue));
org.springframework.session.web.http.DefaultCookieSerializer.writeCookieValue()
在响应中设置Cookie:
response.addCookie(sessionCookie);
实际上并未编写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);
}
问题是included
属性,在某些时候设置为true,阻止添加cookie。
当正在为jsp(使用tile)提供服务时会发生这种情况:
更新
这是将响应标记为包含的时刻(当standard.jsp切片布局插入属性时:
<tiles:insertAttribute name="header" ignore="false"/>
答案 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)
<强>摘要强>
在SessionRepositoryResponseWrapper.onResponseCommitted()中保留breakPoint。
检查SessionRepositoryRequestWrapper中的响应对象是否为非包装响应。 (包括=假)
如果它是一个包装的响应对象,请确保sessionRepositoryFilter是第一个。
=====
当'DispatcherType.INCLUDE(included = true)'时,Spring-session已经处理了这个问题。
SessionRepositoryResponseWrapper.onResponseCommitted()正在尝试将addCookie添加到原始响应对象。
sessionRepositoryFilter必须位于第一个位置,以包装tomcat传递的原始applicationHttpResponse。
问题情况
SessionRepositoryRequestWrapper接收包装的响应并保留它。
在servlet容器中执行doInclude()时,找到原始响应并用ApplicationHttpResponse(included = true)包装它。 然后,SetResponse(新的包装响应)到最里面的包装器。