java - Spring @SessionAttributes 和 "Cannot create a session after the response has been committed"

标签 java spring session spring-mvc

我正在尝试设置和获取 session 属性,但要么我误解了它的工作原理,要么我做错了什么。

请有人解释为什么这不起作用。

我有以下简单的 Spring Web MVC Controller

@Controller
@SessionAttributes("sessid")
@RequestMapping("sesstest")
public class SessTest 
{
    @RequestMapping("in")
    @ResponseBody
    public String in(ModelMap model){
        String uuid = UUID.randomUUID().toString();
        model.addAttribute("sessid", uuid);
        return uuid;
    }

    @RequestMapping("out")
    @ResponseBody
    public String out(@ModelAttribute("sessid") String sesid){
        return sesid;
    }
}

这个类应该只在调用/sesstest/in 时设置一个 session 变量,然后在调用/sesstest/out 时调用它

但是调用/in 时出现如下异常

(堆栈跟踪显示在控制台上,web 输出正常)

java.lang.IllegalStateException: Cannot create a session after the response has been committed
    at org.apache.catalina.connector.Request.doGetSession(Request.java:2872)
    at org.apache.catalina.connector.Request.getSession(Request.java:2249)
    at org.apache.catalina.connector.RequestFacade.getSession(RequestFacade.java:895)
    at org.springframework.web.context.request.ServletRequestAttributes.getSession(ServletRequestAttributes.java:111)
    at org.springframework.web.context.request.ServletRequestAttributes.setAttribute(ServletRequestAttributes.java:161)
    at org.springframework.web.bind.support.DefaultSessionAttributeStore.storeAttribute(DefaultSessionAttributeStore.java:55)
    at org.springframework.web.method.annotation.SessionAttributesHandler.storeAttributes(SessionAttributesHandler.java:124)
    at org.springframework.web.method.annotation.ModelFactory.updateModel(ModelFactory.java:232)
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.getModelAndView(RequestMappingHandlerAdapter.java:879)
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandleMethod(RequestMappingHandlerAdapter.java:782)
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:705)
    at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85)
    at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:959)
    at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:893)
    at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:966)
    at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:857)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:618)
    at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:842)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:725)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:291)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
    at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
    at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:77)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
    at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:85)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:219)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:106)
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:501)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:142)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:88)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:516)
    at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1086)
    at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:659)
    at org.apache.coyote.http11.Http11NioProtocol$Http11ConnectionHandler.process(Http11NioProtocol.java:223)
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1558)
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1515)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
    at java.lang.Thread.run(Thread.java:745)

谢谢!

最佳答案

官方称这是“按设计工作”。

在这种情况下,各种解决方法是:

  1. 手动开始 session
  2. 使用过滤器确保 session 是 出席
  3. 使用模型的 View 渲染。

请在此处查看 Rossen 的明确回复:https://jira.spring.io/browse/SPR-12877

The scenario is somewhat unusual since typically model attributes are used for rendering with views (e.g. HTML template). For @ResponseBody only the return value is used to render the response. That said the use of @ResponseBody doesn't preclude the use of @SessionAttributes. The error has to do with trying to create the session for the first time too late. Normally the use of something like Spring Security with a Filter to store authentication in the session ensures there is always an HTTP session. In the absence of that you could add your own Filter or HandlerInterceptor that simply calls request.getSession(true). That's enough to ensure a session is present.

不能反驳。

关于java - Spring @SessionAttributes 和 "Cannot create a session after the response has been committed",我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29381181/

相关文章:

apache - 如何将本地主机应用程序服务器从 Apache httpd 更改为 ColdFusion 10 中内置的 Tomcat?

java - 如何将类(class)更改为公开类(class)?

Java/PostgreSQL-CallableStatement.setBoolean null 抛出 NPE

java - Spring @Transactional 在 Hibernate 中产生问题

java - 在 Spring Security 登录期间添加 cookie

php - 如何在 slider 更改时在 JavaScript 中取消设置 session

java - 我可以只使用一张表进行所有 hibernate 环境审计吗?

java - 如何编写高效的背景图像

java - 将xml解析为java对象

php - 使用 PDO 插入 session 数据