添加<h:form>会导致java.lang.IllegalStateException:响应提交后无法创建会话

在添加<h:form>之后,我在一个非常简单的JSF 2页面中遇到以下异常:

 java.lang.IllegalStateException: Cannot create a session after the response has been committed at org.apache.catalina.connector.Request.doGetSession(Request.java:2758) at org.apache.catalina.connector.Request.getSession(Request.java:2268) 

我在Tomcat 7.0.22和JDK 7上使用Mojarra 2.1.3和PrimeFaces3.0M4。

该页面是一个非常基本的数据表格:

 <html xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://java.sun.com/jsf/html" xmlns:f="http://java.sun.com/jsf/core" xmlns:p="http://primefaces.org/ui"> <h:head> </h:head> <h:body> <h:form> <p:dataTable var="car" value="#{tableBean.cars}"> ...... </p:dataTable> </h:form> </h:body> </html> 

该页面在浏览器上正确显示,但在控制台上,我看到异常。 如果我删除<h:form> ,异常消失。

这是如何造成的,我该如何解决?

这是一个已知的问题,并且已经被你的问题报告为问题2215 。 当响应缓冲区已经溢出(由于内容较大),并且在创建会话之前已经提交了响应时,会发生这种情况。 这是Mojarra试图尽可能地推迟“不必要的”会话创造(尽管它本身是一件好事)的过分努力的结果。

直到他们得到解决,有几个解决方法:

  1. 创建FilterChain#doFilter()之前的HttpServletRequest#getSession() FilterChain#doFilter() 。 优点:无需更改JSF配置/代码。 缺点:当你想避免不必要的会话创建。

  2. 在Bean的(后)构造函数或preRenderView侦听器中调用ExternalContext#getSession()true 。 优点:其实,没有什么。 缺点:太hacky。

  3. 添加一个名为com.sun.faces.writeStateAtFormEnd且值为false的上下文参数给web.xml 。 好处:不必要的会话创建将被真正避免,而不是#1和#2。 缺点:响应现在将完全缓冲在内存中,直到到达</h:form> 。 如果你的表格不是非常大,那么影响应该是最小的。 但是,如果您的<h:form>在视图中启动得相对较晚,它仍然会失败。 这可能与#4结合。

  4. 添加一个名为javax.faces.FACELETS_BUFFER_SIZE的上下文参数和一个以字节为单位的Facelets响应缓冲区大小的值(例如,对于64KB为65535 ),以便整个HTML输出或至少<h:form> (见#3)在响应缓冲区中。 优点/缺点,见#3。

  5. 将名为javax.faces.STATE_SAVING_METHOD的上下文参数和client值添加到web.xml 。 优点:除非有会话范围的bean,否则根本不会创建会话。 它也立即解决了潜在的ViewExpiredException情况。 缺点:增加网络带宽使用。 如果您正在使用部分状态保存,那么影响应该是最小的。

至于为什么当你移除<h:form>时问题消失,这是因为为了存储视图状态,不需要创建任何会话。


更新 :自从Mojarra 2.1.8以来,已经修复了重复的问题2277 。 所以,你也可以升级到至少那个版本。

随着javax.faces昨天发布的新版本2.1.21这个问题似乎已经消失。 声明新版本:

 <dependency> <groupId>org.glassfish</groupId> <artifactId>javax.faces</artifactId> <version>2.1.21</version> </dependency> 

并替换glassfish模块文件夹中的javax.faces.jar,替换新版本2.1.21的javax.faces.jar。

在我的情况下(myfaces-2.2.8和Tomcat 8.0.23),问题是web.xmlwelcome-file的一个错字。 在我看到的调试过程中,Tomcat按照预期创建了一个404,但不知何故,表面试图在之后访问会话,这导致了java.lang.IllegalStateException: Cannot create a session after the response has been committed 。 在web.xml welcome-file中使用有效的页面为我解决了这个问题。

您可能需要在h:form元素之前和之后添加<f:view></f:view> ,并为jsf标记添加html标记的链接

 <html xmlns:f="http://java.sun.com/jsf/core"> 

为此工作。

如果你使用的是Spring MVC,而且Spring是由Spring Forms调用的,那么我们应该使用GET方法而不是POST(来获取数据),并且不应该有输入字段,我们可以使用intead。