Spring 使用 Tiles 时会话在 Tomcat 8 上不工作 - 会话 Cookie 未设置,因为已包含响应
Spring Session not working on Tomcat 8 when using Tiles - SESSION Cookie is not set as response is already included
我在 Spring 引导项目上使用 Spring Session 1.2。0.RELEASE。这被打包为 war 并部署在 Tomcat 8.
我已遵循 Spring 会话文档并正确配置了它。问题是应用程序的入口点是一个控制器,它在会话上设置了一些值,但 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(使用磁贴)正在维修时会发生这种情况:
更新:
这是响应被标记为包含的时刻(当 standard.jsp tiles 布局插入属性时:
<tiles:insertAttribute name="header" ignore="false"/>
为了解决这个问题,我最终创建了一个过滤器来强制创建会话。
正如所见,对控制器的第一次调用没有添加 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() {}
}
总结
在SessionRepositoryResponseWrapper.onResponseCommitted()中保持断点。
检查 SessionRepositoryRequestWrapper 中的响应对象是否为非包装响应。 (包含 = 假)
如果是包装响应对象,确保sessionRepositoryFilter在前。
================
Spring-session在'DispatcherType.INCLUDE (included = true)'.
时已经在处理问题
SessionRepositoryResponseWrapper.onResponseCommitted() 正在尝试向原始响应对象添加 Cookie。
sessionRepositoryFilter 必须位于第一个位置以包装由 tomcat 传递的原始 applicationHttpResponse。
问题情况
SessionRepositoryRequestWrapper 接收包装的响应并保存它。
在servlet容器中执行doInclude()时,找到原来的reponse,用ApplicationHttpResponse(included = true)包裹起来。
然后,SetResponse(新包装响应)到最里面的包装器。
- Spring-session 对存储在 SessionRepositoryResponseWrapper.onResponseCommitted() 中的响应(期望原始响应)执行 addCookie,但它不能,因为它设置为 'included = true'.
我在 Spring 引导项目上使用 Spring Session 1.2。0.RELEASE。这被打包为 war 并部署在 Tomcat 8.
我已遵循 Spring 会话文档并正确配置了它。问题是应用程序的入口点是一个控制器,它在会话上设置了一些值,但 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(使用磁贴)正在维修时会发生这种情况:
更新:
这是响应被标记为包含的时刻(当 standard.jsp tiles 布局插入属性时:
<tiles:insertAttribute name="header" ignore="false"/>
为了解决这个问题,我最终创建了一个过滤器来强制创建会话。
正如所见,对控制器的第一次调用没有添加 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() {}
}
总结
在SessionRepositoryResponseWrapper.onResponseCommitted()中保持断点。
检查 SessionRepositoryRequestWrapper 中的响应对象是否为非包装响应。 (包含 = 假)
如果是包装响应对象,确保sessionRepositoryFilter在前。
================
Spring-session在'DispatcherType.INCLUDE (included = true)'.
时已经在处理问题SessionRepositoryResponseWrapper.onResponseCommitted() 正在尝试向原始响应对象添加 Cookie。
sessionRepositoryFilter 必须位于第一个位置以包装由 tomcat 传递的原始 applicationHttpResponse。
问题情况
SessionRepositoryRequestWrapper 接收包装的响应并保存它。
在servlet容器中执行doInclude()时,找到原来的reponse,用ApplicationHttpResponse(included = true)包裹起来。 然后,SetResponse(新包装响应)到最里面的包装器。
- Spring-session 对存储在 SessionRepositoryResponseWrapper.onResponseCommitted() 中的响应(期望原始响应)执行 addCookie,但它不能,因为它设置为 'included = true'.