添加<h:form>导致java.lang.IllegalStateException: Cannot create a session after the response has been committed。

47

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

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)

我正在使用Mojarra 2.1.3和PrimeFaces 3.0M4,Tomcat 7.0.22和JDK 7。

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

<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>,则此异常会消失。

这是什么原因造成的,我该如何解决?

5个回答

83

这是一个已知的问题,我已经报告过了,问题编号为2215。当响应缓冲区溢出(由于内容过大)并且在会话被创建之前响应已经提交时,就会发生这种情况。这是Mojarra过于热心地尽可能延迟“不必要”的会话创建导致的结果(虽然本质上这是件好事)。

在他们解决这个问题之前,有几个解决方法:

  1. 创建一个 Filter ,在调用FilterChain#doFilter()之前调用HttpServletRequest#getSession()。优点:无需更改JSF配置或代码。缺点:如果您自己也想避免不必要的会话创建,则不适用。

  2. 在bean(后置)构造函数或preRenderView监听器中用true 调用ExternalContext#getSession()。优点:实际上没有什么优点。缺点:太过于hacky。

  • web.xml中添加一个名为com.sun.faces.writeStateAtFormEnd的上下文参数,值为false。优点:与 #1 和 #2 不同,将真正避免创建不必要的会话。缺点:响应将完全缓存在内存中,直到达到 </h:form>。如果您的表单不是非常大,影响应该是很小的。但是,如果您的 <h:form> 在视图中相对较晚,它仍然会失败。这可以与 #4 结合使用。

  • web.xml中添加一个名为javax.faces.FACELETS_BUFFER_SIZE的上下文参数,并设置 Facelets 响应缓冲区大小的值(例如,64KB 的值为 65535),以便整个 HTML 输出或至少是 <h:form>(参见 #3)适合响应缓冲区。优点/缺点,参见 #3。

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

  • 至于为什么删除<h:form>后问题消失,这是因为不需要创建会话来存储视图状态。


    更新:根据重复的issue 2277,自 Mojarra 2.1.8 版本以来已经修复了此问题。因此,您也可以升级到至少该版本。


    1
    看起来这个问题将会在Mojarra 2.1.8中得到解决(http://java.net/jira/browse/JAVASERVERFACES-2277),该版本应该很快发布。 - wemu
    1
    阅读整个JIRA,似乎问题仍然存在,2.1.16。 - OCB
    我曾经遇到过类似的问题,虽然我使用的是2.1.13版本,但问题仍然存在。然而,实施第三条建议解决了这个问题。 - Balázs Németh

    6

    随着昨天发布的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。


    3
    在我的情况下(myfaces-2.2.8和Tomcat 8.0.23),问题是在web.xmlwelcome-file中有一个错别字。在调试时,我发现Tomcat按预期创建了404,但某种方式下myfaces尝试访问Session,这导致java.lang.IllegalStateException: Cannot create a session after the response has been committed。在web.xmlwelcome-file中使用有效页面为我解决了问题。

    0
    你可能需要在h:form元素前后添加一个<f:view></f:view>,并且为JSF标签的HTML标记添加链接。
    <html xmlns:f="http://java.sun.com/jsf/core">
    

    为了使这个工作正常运行。


    -1
    如果您正在使用Spring MVC并且是由Spring Forms发出调用,则我们应该使用GET方法而不是POST(以获取数据),并且不应该有输入字段,可以使用其他方式。

    <form:form method="get" action="#" id="viewAllHospital" class="validateForm" modelAttribute="hccHospitalUserInfoForm"> <a href="/view/B2CSuperAdminProfileComponentController?viewAllHospital=true">查看所有医院</a> </form:form> - user2645432

    网页内容由stack overflow 提供, 点击上面的
    可以查看英文原文,
    原文链接