Agregar hace que java.lang.IllegalStateException: No se puede crear una sesión después de que la respuesta se haya confirmado

Me enfrento a la siguiente excepción en una página JSF 2 muy simple después de agregar :

 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) 

Estoy usando Mojarra 2.1.3 y PrimeFaces3.0M4, en Tomcat 7.0.22 y JDK 7.

La página es una tabla de datos muy básica:

      

......

La página se muestra correctamente en el navegador, pero en la consola veo la excepción. La Excepción desaparece si elimino la .

¿Cómo es esto causado y cómo puedo resolverlo?

Este es un problema conocido y ha sido informado por los tuyos realmente como el problema 2215 . Esto ocurrirá cuando el búfer de respuesta se haya desbordado (debido a un gran contenido) y la respuesta se haya confirmado antes de que se haya creado la sesión. Esto es el resultado de los bashs poco entusiastas de Mojarra para posponer la creación de sesión “innecesaria” tanto como sea posible (lo cual es en sí mismo una buena cosa).

Hasta que lo solucionen, existen varias soluciones:

  1. Cree un Filter que haga HttpServletRequest#getSession() antes de FilterChain#doFilter() . Ventaja: no es necesario cambiar la configuración / código JSF. Desventaja: cuando también quiere evitar la creación innecesaria de sesiones.

  2. Llame a ExternalContext#getSession() con true en el constructor de bean (post) o en el listener de preRenderView . Ventaja: en realidad, nada. Desventaja: demasiado hacky.

  3. Agregue un parámetro de contexto con el nombre de com.sun.faces.writeStateAtFormEnd y el valor de false a web.xml . Ventaja: realmente se evitará la creación innecesaria de sesiones en lugar de # 1 y # 2. Desventaja: la respuesta ahora estará totalmente almacenada en la memoria hasta que se llegue a . Si sus formularios no son extremadamente grandes, el impacto debería ser mínimo. Sin embargo, aún fallaría si su comienza relativamente tarde en la vista. Esto se puede combinar con el # 4.

  4. Agregue un parámetro de contexto con el nombre de javax.faces.FACELETS_BUFFER_SIZE y un valor del tamaño del búfer de respuesta de Facelets en bytes (por ejemplo, 65535 para 64 KB) para que todo el resultado HTML o al menos el (vea n. ° 3) coincida en el buffer de respuesta. Ventaja / desventaja, ver # 3.

  5. Agregue un parámetro de contexto con el nombre de javax.faces.STATE_SAVING_METHOD y el valor del client a web.xml . Ventaja: la sesión no se creará en absoluto a menos que tenga beans de ámbito de sesión. También resuelve de forma inmediata los posibles casos de ViewExpiredException . Desventaja: aumento en el uso del ancho de banda de la red. Si está utilizando el ahorro de estado parcial, entonces el impacto debería ser mínimo.

En cuanto a por qué el problema desaparece cuando elimina , esto se debe a que no es necesario crear ninguna sesión para almacenar el estado de la vista.


Actualización : esto tiene como el problema duplicado 2277 se ha corregido desde Mojarra 2.1.8. Entonces, también puedes simplemente actualizar a al menos esa versión.

Con la nueva versión 2.1.21 lanzada ayer de javax.faces, este problema parece haber desaparecido. Declara la nueva versión:

  org.glassfish javax.faces 2.1.21  

y reemplace javax.faces.jar en la carpeta de módulos glassfish reemplazando javax.faces.jar para la nueva versión 2.1.21.

En mi caso (myfaces-2.2.8 y Tomcat 8.0.23) el problema era un error ortográfico en el welcome-file de welcome-file de web.xml . Mientras depuraba, vi que Tomcat creaba un 404 como se esperaba, pero de alguna manera mis caras intentaron acceder posteriormente a la sesión, lo que provocó una java.lang.IllegalStateException: Cannot create a session after the response has been committed . El uso de una página válida en welcome-file de web.xml solucionó el problema.

Es posible que necesite agregar un y antes y después de h:form elements, además de agregar el enlace a su etiqueta html para las tags jsf

  

para que esto funcione

Si está utilizando Spring MVC y la convocatoria está hecha por Spring Forms, entonces deberíamos usar el método GET en lugar de POST (para obtener datos) y no debería haber ningún campo de entrada que podamos usar intead.