java.lang.IllegalStateException: impossible (forward | sendRedirect | create session) après que la réponse a été validée

96

Cette méthode jette

java.lang.IllegalStateException: impossible de transférer après que la réponse a été validée

et je suis incapable de repérer le problème. De l'aide?

    int noOfRows = Integer.parseInt(request.getParameter("noOfRows"));
    String chkboxVal = "";
    // String FormatId=null;
    Vector vRow = new Vector();
    Vector vRow1 = new Vector();
    String GroupId = "";
    String GroupDesc = "";
    for (int i = 0; i < noOfRows; i++) {
        if ((request.getParameter("chk_select" + i)) == null) {
            chkboxVal = "notticked";
        } else {
            chkboxVal = request.getParameter("chk_select" + i);
            if (chkboxVal.equals("ticked")) {
                fwdurl = "true";
                Statement st1 = con.createStatement();
                GroupId = request.getParameter("GroupId" + i);
                GroupDesc = request.getParameter("GroupDesc" + i);
                ResultSet rs1 = st1
                        .executeQuery("select FileId,Description from cs2k_Files "
                                + " where FileId like 'M%' and co_code = "
                                + ccode);
                ResultSetMetaData rsm = rs1.getMetaData();
                int cCount = rsm.getColumnCount();

                while (rs1.next()) {
                    Vector vCol1 = new Vector();
                    for (int j = 1; j <= cCount; j++) {
                        vCol1.addElement(rs1.getObject(j));
                    }
                    vRow.addElement(vCol1);
                }
                rs1 = st1
                        .executeQuery("select FileId,NotAllowed from cs2kGroupSub "
                                + " where FileId like 'M%' and GroupId = '"
                                + GroupId + "'" + " and co_code = " + ccode);
                rsm = rs1.getMetaData();
                cCount = rsm.getColumnCount();

                while (rs1.next()) {
                    Vector vCol2 = new Vector();
                    for (int j = 1; j <= cCount; j++) {
                        vCol2.addElement(rs1.getObject(j));
                    }
                    vRow1.addElement(vCol2);
                }

                // throw new Exception("test");

                break;
            }
        }
    }
    if (fwdurl.equals("true")) {
        // throw new Exception("test");
        // response.sendRedirect("cs2k_GroupCopiedUpdt.jsp") ;
        request.setAttribute("GroupId", GroupId);
        request.setAttribute("GroupDesc", GroupDesc);
        request.setAttribute("vRow", vRow);
        request.setAttribute("vRow1", vRow1);
        getServletConfig().getServletContext().getRequestDispatcher(
                "/GroupCopiedUpdt.jsp").forward(request, response);
    }
sansknwoledge
la source
4
C'est difficile à voir comme ça, mais il semble que vous ayez déjà envoyé une sortie avant votre transfert. Pourriez-vous s'il vous plaît imprimer le code complet et vérifier si vous n'avez pas de filtre en place?
Kartoch

Réponses:

244

Un malentendu courant parmi les débutants est qu'ils pensent que l'appel d'un forward(), sendRedirect()ou sendError()sortirait comme par magie et "sauterait" hors du bloc de méthode, ignorant ainsi le reste du code. Par exemple:

protected void doXxx() {
    if (someCondition) {
        sendRedirect();
    }
    forward(); // This is STILL invoked when someCondition is true!
}

Ce n'est donc en fait pas vrai. Ils ne se comportent certainement pas différemment des autres méthodes Java (attendez System#exit()bien sûr). Lorsque l' someConditionexemple ci-dessus est trueet que vous appelez ainsi forward()après sendRedirect()ou sendError()sur la même requête / réponse, il y a de grandes chances que vous obteniez l'exception:

java.lang.IllegalStateException: impossible de transférer après que la réponse a été validée

Si l' ifinstruction appelle a forward()et que vous appelez ensuite sendRedirect()ou sendError(), alors l'exception ci-dessous sera levée:

java.lang.IllegalStateException: Impossible d'appeler sendRedirect () une fois la réponse validée

Pour résoudre ce problème, vous devez soit ajouter une return;déclaration par la suite

protected void doXxx() {
    if (someCondition) {
        sendRedirect();
        return;
    }
    forward();
}

... ou pour introduire un bloc else.

protected void doXxx() {
    if (someCondition) {
        sendRedirect();
    } else {
        forward();
    }
}

Pour déterminer la cause principale dans votre code, recherchez simplement n'importe quelle ligne qui appelle a forward(), sendRedirect()ou sendError()sans quitter le bloc de méthode ou en ignorant le reste du code. Cela peut être à l'intérieur du même servlet avant la ligne de code particulière, mais aussi dans n'importe quel servlet ou filtre qui a été appelé avant le servlet particulier.

Dans le cas de sendError(), si votre seul objectif est de définir l'état de la réponse, utilisez à la setStatus()place.


Une autre cause probable est que le servlet écrit dans la réponse tandis que a forward()sera appelé, ou a été appelé dans la même méthode.

protected void doXxx() {
    out.write("some string");
    // ... 
    forward(); // Fail!
}

La taille du tampon de réponse par défaut dans la plupart des serveurs est de 2 Ko, donc si vous y écrivez plus de 2 Ko, il sera validé et forward()échouera de la même manière:

java.lang.IllegalStateException: impossible de transférer après que la réponse a été validée

La solution est évidente, n'écrivez simplement pas dans la réponse dans le servlet. C'est la responsabilité du JSP. Vous venez de définir un attribut de requête comme ceci request.setAttribute("data", "some string"), puis de l'imprimer dans JSP comme tel ${data}. Consultez également notre page wiki Servlets pour apprendre à utiliser correctement les servlets.


Une autre cause probable est que le servlet écrit un téléchargement de fichier dans la réponse après quoi, par exemple, a forward()est appelé.

protected void doXxx() {
    out.write(bytes);
    // ... 
    forward(); // Fail!
}

Ceci n'est techniquement pas possible. Vous devez supprimer l' forward()appel. L'utilisateur final restera sur la page actuellement ouverte. Si vous avez réellement l'intention de modifier la page après un téléchargement de fichier, vous devez déplacer la logique de téléchargement de fichier vers le chargement de page de la page cible.


Une autre cause probable est que les méthodes forward(), sendRedirect()ou sendError()sont invoquées via du code Java intégré dans un fichier JSP sous la forme d'une méthode à l'ancienne <% scriptlets %>, une pratique officiellement déconseillée depuis 2001 . Par exemple:

<!DOCTYPE html>
<html lang="en">
    <head>
        ... 
    </head>
    <body>
        ...

        <% sendRedirect(); %>
        
        ...
    </body>
</html>

Le problème ici est que JSP écrit en interne immédiatement le texte du modèle (c'est-à-dire le code HTML) out.write("<!DOCTYPE html> ... etc ...")dès qu'il le rencontre. Il s'agit donc essentiellement du même problème que celui expliqué dans la section précédente.

La solution est évidente, n'écrivez pas de code Java dans un fichier JSP. C'est la responsabilité d'une classe Java normale telle qu'un servlet ou un filtre. Consultez également notre page wiki Servlets pour apprendre à utiliser correctement les servlets.


Voir également:


Sans rapport avec votre problème concret, votre code JDBC perd des ressources. Corrigez cela également. Pour obtenir des conseils, voir également À quelle fréquence les connexions, instructions et ResultSet doivent-elles être fermées dans JDBC?

BalusC
la source
2
Avec une pause tu veux dire break;? Cela signifierait que le code était à l'intérieur d'une forou d'une whileboucle dans laquelle le a forward()été appelé à plusieurs reprises pendant la boucle (ce qui est donc incorrect, vous ne devriez appeler en avant qu'une fois APRÈS la boucle - ou pour vous débarrasser de la boucle car elle n'est apparemment pas nécessaire) .
BalusC
@BalusC Avez-vous une idée sur ce problème connexe? stackoverflow.com/questions/18658021/…
confilez le
@confile: Je ne fais pas Grails, mais basé sur la pile d'appels, il effectue toujours un forward()appel alors qu'il ne devrait pas le faire. JSF, que je connais bien, le fait également à moins que vous n'appeliez explicitement FacesContext#responseComplete(). Cette question connexe (que j'ai trouvée en utilisant les mots-clés "les grails empêchent la réponse de rendu") peut être utile: stackoverflow.com/questions/5708654/…
BalusC
@BalusC Grails est essentiellement Java, mais le problème est lié aux servlets. Avez-vous une autre idée de ce que je peux faire. Je mets un retour après chaque rendu, redirige et avant comme vous l'avez suggéré.
confilez le
@confile: Je sais. J'ai déjà répondu à la cause: Grails est toujours en train d'effectuer un forward()appel alors qu'il ne devrait pas le faire. La solution est fonctionnellement évidente: dites-lui de ne pas faire cela. Il n'avait aucune idée que vous aviez repris par programme le travail que Grails était censé faire: gérer la réponse. Techniquement, je ne sais pas comment dire cela à Grails. Mais je sais que beaucoup d'autres frameworks MVC prennent en charge cela (étant chargé de ne pas gérer la réponse par lui-même), tels que JSF, Spring MVC, Wicket, etc. Je serais surpris si cela est impossible dans Grails.
BalusC le
19

même l'ajout d'une instruction return soulève cette exception, pour laquelle seule solution est ce code:

if(!response.isCommitted())
// Place another redirection
user1503117
la source
6

En règle générale, vous voyez cette erreur après avoir déjà effectué une redirection, puis essayez de générer plus de données dans le flux de sortie. Dans les cas où j'ai vu cela dans le passé, c'est souvent l'un des filtres qui essaie de rediriger la page, puis la transmet toujours au servlet. Je ne vois rien de mal immédiatement avec le servlet, donc vous voudrez peut-être essayer de jeter un œil aux filtres que vous avez également en place.

Edit : Aide supplémentaire pour diagnostiquer le problème…

La première étape pour diagnostiquer ce problème consiste à déterminer exactement où l'exception est levée. Nous supposons qu'il est jeté par la ligne

getServletConfig().getServletContext()
                  .getRequestDispatcher("/GroupCopiedUpdt.jsp")
                  .forward(request, response);

Mais vous constaterez peut-être qu'il est lancé plus tard dans le code, où vous essayez de sortir vers le flux de sortie après avoir essayé de faire le transfert. Si cela vient de la ligne ci-dessus, cela signifie que quelque part avant cette ligne, vous avez soit:

  1. les données de sortie vers le flux de sortie, ou
  2. fait une autre redirection au préalable.

Bonne chance!

Paul Wagland
la source
2

Ceci est dû au fait que votre servlet tente d'accéder à un objet de requête qui n'existe plus. L'instruction forward ou include d'un servlet n'arrête pas l'exécution du bloc de méthode. Il continue jusqu'à la fin du bloc de méthode ou de la première instruction de retour comme toute autre méthode java.

La meilleure façon de résoudre ce problème consiste simplement à définir la page (où vous supposez transférer la demande) de manière dynamique en fonction de votre logique. C'est:

protected void doPost(request , response){
String returnPage="default.jsp";
if(condition1){
 returnPage="page1.jsp";
}
if(condition2){
   returnPage="page2.jsp";
}
request.getRequestDispatcher(returnPage).forward(request,response); //at last line
}

et ne faire avancer qu'une seule fois à la dernière ligne ...

vous pouvez également résoudre ce problème en utilisant l'instruction return après chaque forward () ou mettre chaque forward () dans if ... else bloc

Suman Sengupta
la source
2

j'ai enlevé

        super.service(req, res);

Puis ça a bien fonctionné pour moi

kartikag01
la source
2

Bosse...

J'ai juste eu la même erreur. J'ai remarqué que j'invoquais super.doPost(request, response);lors de la substitution de la doPost()méthode et en invoquant explicitement le constructeur de la superclasse

    public ScheduleServlet() {
        super();
        // TODO Auto-generated constructor stub
    }

Dès que j'ai commenté la déclaration super.doPost(request, response);de l'intérieur doPost(), cela a parfaitement fonctionné ...

protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        //super.doPost(request, response);
        // More code here...

}

Inutile de dire que j'ai besoin de relire les super()meilleures pratiques: p

John Rambo
la source
1

Vous devez ajouter une instruction return pendant que vous transférez ou redirigez le flux.

Exemple:

si forwardind,

    request.getRequestDispatcher("/abs.jsp").forward(request, response);
    return;

en cas de redirection,

    response.sendRedirect(roundTripURI);
    return;
Ashish Mishra
la source
0

Après la méthode de retour en avant, vous pouvez simplement faire ceci:

return null;

Cela brisera la portée actuelle.

Amir Amiri
la source