使用Tiles时,Spring会话在Tomcat 8上不工作-会话Cookie未设置为已包含响应
我在一个SpringBoot项目上使用SpringSession1.2.0.RELEASE。这被打包为war并部署在Tomcat8上 我遵循了Spring会话文档并正确地配置了它。问题在于,应用程序的入口点是一个控制器,该控制器在会话上设置一些值,但会话cookie不会发送到浏览器 我看到:使用Tiles时,Spring会话在Tomcat 8上不工作-会话Cookie未设置为已包含响应,spring,tomcat,spring-boot,tomcat8,spring-session,Spring,Tomcat,Spring Boot,Tomcat8,Spring Session,我在一个SpringBoot项目上使用SpringSession1.2.0.RELEASE。这被打包为war并部署在Tomcat8上 我遵循了Spring会话文档并正确地配置了它。问题在于,应用程序的入口点是一个控制器,该控制器在会话上设置一些值,但会话cookie不会发送到浏览器 我看到: org.springframework.session.web.http.CookieHttpSessionStrategy.onNewSession()尝试编写cookie: this.cookieSer
org.springframework.session.web.http.CookieHttpSessionStrategy.onNewSession()
尝试编写cookie:
this.cookieSerializer
.writeCookieValue(新的CookieValue(请求、响应、CookieValue))代码>
org.springframework.session.web.http.DefaultCookieSerializer.writeCookieValue()
在响应中设置cookie:
response.addCookie(sessioncokie)代码>
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(使用tiles)正在接受服务时会发生这种情况:
更新:
此时响应被标记为包含(standard.jsp tiles layout插入属性时:
为了解决这个问题,我最终创建了一个过滤器来强制创建会话 如图所示,对控制器的第一次调用没有添加cookie,因为在Tiles JSP呈现期间,响应已经标记为包含。我所做的是在筛选器中强制创建会话,并重定向请求相同的requestURI。这样,因为调用不涉及呈现cookie的Tiles,所以创建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() {}
}
为了解决这个问题,我最终创建了一个过滤器来强制创建会话 如图所示,对控制器的第一次调用没有添加cookie,因为在Tiles JSP呈现期间,响应已经标记为包含。我所做的是在筛选器中强制创建会话,并重定向请求相同的requestURI。这样,因为调用不涉及呈现cookie的Tiles,所以创建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() {}
}
摘要
- SessionRepositoryRequestWrapper接收包装好的响应并保存它
- 在servlet容器中执行doInclude()时,找到原始响应并用ApplicationHttpResponse(include=true)包装它。 然后,将SetResponse(新包装响应)设置为最里面的包装
- Spring会话对存储在SessionRepositoryResponseWrapper.onResponseCommitted()中的响应(应为原始响应)执行addCookie,但无法执行,因为它被设置为“included=true”
- 在SessionRepositoryResponseWrapper.onResponseCommitted()中保留断点
- 检查SessionRepositoryRequestWrapper内的响应对象是否为非包装响应。(include=false)
- 如果它是包装响应对象,请确保首先使用sessionRepositoryFilter ================ 当“DispatcherType.INCLUDE(INCLUDE=true)”时,Spring会话已在处理该问题 SessionRepositoryResponseWrapper.onResponseCommitted()正在尝试将Cookie添加到原始响应对象 sessionRepositoryFilter必须位于第一个位置,才能包装tomcat传递的原始applicationHttpResponse 问题情况
- SessionRepositoryRequestWrapper接收包装好的响应并保存它
- 在servlet容器中执行doInclude()时,找到原始响应并用ApplicationHttpResponse(include=true)包装它。 然后,将SetResponse(新包装响应)设置为最里面的包装
- Spring会话对存储在SessionRepositoryResponseWrapper.onResponseCommitted()中的响应(应为原始响应)执行addCookie,但无法执行,因为它被设置为“included=true”
- 摘要