添加<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试图尽可能地推迟“不必要的”会话创造(尽管它本身是一件好事)的过分努力的结果。
直到他们得到解决,有几个解决方法:
-
创建
FilterChain#doFilter()
之前的HttpServletRequest#getSession()
FilterChain#doFilter()
。 优点:无需更改JSF配置/代码。 缺点:当你想避免不必要的会话创建。 -
在Bean的(后)构造函数或
preRenderView
侦听器中调用ExternalContext#getSession()
与true
。 优点:其实,没有什么。 缺点:太hacky。 -
添加一个名为
com.sun.faces.writeStateAtFormEnd
且值为false
的上下文参数给web.xml
。 好处:不必要的会话创建将被真正避免,而不是#1和#2。 缺点:响应现在将完全缓冲在内存中,直到到达</h:form>
。 如果你的表格不是非常大,那么影响应该是最小的。 但是,如果您的<h:form>
在视图中启动得相对较晚,它仍然会失败。 这可能与#4结合。 -
添加一个名为
javax.faces.FACELETS_BUFFER_SIZE
的上下文参数和一个以字节为单位的Facelets响应缓冲区大小的值(例如,对于64KB为65535
),以便整个HTML输出或至少<h:form>
(见#3)在响应缓冲区中。 优点/缺点,见#3。 -
将名为
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.xml
的welcome-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。