L’aggiunta di causa java.lang.IllegalStateException: imansible creare una sessione dopo che la risposta è stata commessa

Sto affrontando la seguente eccezione in una pagina JSF 2 molto semplice dopo aver aggiunto :

 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) 

Sto usando Mojarra 2.1.3 e PrimeFaces3.0M4, su Tomcat 7.0.22 e JDK 7.

La pagina è una tabella di dati molto semplice:

      

......

La pagina mostra correttamente nel browser, ma sulla console vedo l’eccezione. L’eccezione scompare se rimuovo .

Come è causato e come posso risolverlo?

Questo è un problema noto ed è stato segnalato dal sottoscritto come numero 2215 . Ciò si verifica quando il buffer di risposta ha overflow (a causa di contenuti di grandi dimensioni) e la risposta è stata confermata prima che la sessione sia stata creata. Questo è il risultato di alcuni tentativi eccessivamente zelanti di Mojarra di posticipare il più ansible la creazione di sessioni “non necessarie” (che è comunque una buona cosa).

Fino a quando non vengono risolti, esistono diversi soluzioni:

  1. Crea un Filter che fa HttpServletRequest#getSession() prima di FilterChain#doFilter() . Vantaggio: non è necessario modificare la configurazione / codice JSF. Svantaggio: quando si desidera evitare anche la creazione di sessioni non necessarie.

  2. Chiama ExternalContext#getSession() con true nel programma di costruzione (post) di preRenderView o listener di preRenderView . Vantaggio: in realtà, niente. Svantaggio: troppo hacky.

  3. Aggiungere un parametro di contesto con nome di com.sun.faces.writeStateAtFormEnd e valore di false a web.xml . Vantaggio: la creazione di sessioni non necessarie sarà davvero evitata rispetto a # 1 e # 2. Svantaggio: la risposta verrà ora completamente memorizzata nella memoria finché non viene raggiunto . Se le tue forms non sono estremamente grandi, l’impatto dovrebbe comunque essere minimo. Tuttavia, fallirebbe comunque se inizia relativamente tardi nella visualizzazione. Questo può essere combinato con # 4.

  4. Aggiungi un parametro di contesto con il nome di javax.faces.FACELETS_BUFFER_SIZE e un valore della dimensione del buffer di risposta Facelets in byte (ad esempio 65535 per 64 KB) in modo che l’intero output HTML o almeno il (vedi # 3) si adatti nel buffer di risposta. Vantaggio / svantaggio, vedi # 3.

  5. Aggiungi un parametro di contesto con il nome di javax.faces.STATE_SAVING_METHOD e il valore del client su web.xml . Vantaggio: la sessione non verrà creata a meno che non si disponga di bean con scope di sessione. Risolve immediatamente anche i potenziali casi ViewExpiredException . Svantaggio: maggiore utilizzo della larghezza di banda della rete. Se stai utilizzando il salvataggio parziale dello stato, l’impatto dovrebbe comunque essere minimo.

Per quanto riguarda il motivo per cui il problema scompare quando si rimuove , questo perché non è necessario creare alcuna sessione per memorizzare lo stato di visualizzazione.


Aggiornamento : questo ha come duplicato il problema 2277 dal Mojarra 2.1.8. Quindi, puoi anche solo aggiornare ad almeno quella versione.

Con la nuova versione 2.1.21 rilasciata ieri su javax.faces, questo problema sembra essere scomparso. Dichiara la nuova versione:

  org.glassfish javax.faces 2.1.21  

e sostituire javax.faces.jar nella cartella dei moduli glassfish sostituendo javax.faces.jar per la nuova versione 2.1.21.

Nel mio caso (myfaces-2.2.8 e Tomcat 8.0.23) il Problema era un refuso nel welcome-file di welcome-file di web.xml . Durante il debug ho visto che Tomcat ha creato come previsto un 404, ma in qualche modo i myfaces hanno provato ad accedere successivamente alla Session, che ha causato quindi un java.lang.IllegalStateException: Cannot create a session after the response has been committed . L’utilizzo di una pagina valida nel welcome-file di welcome-file di web.xml risolto il problema per me.

Potrebbe essere necessario aggiungere un e prima e dopo h:form elementi del h:form , inoltre aggiungi il link al tuo tag html per i tag jsf

  

per questo funziona.

Se utilizzi Spring MVC e la chiamata viene effettuata da Spring Forms, dovremmo utilizzare il metodo GET anziché il POST (per recuperare i dati) e non ci dovrebbero essere campi di input che possiamo usare intead.