java.lang.IllegalStateException: Kann nicht weitergeleitet werden (forward | sendRedirect | create session), nachdem die Antwort festgeschrieben wurde

96

Diese Methode wirft

java.lang.IllegalStateException: Kann nicht weitergeleitet werden, nachdem die Antwort festgeschrieben wurde

und ich kann das Problem nicht erkennen. Irgendeine Hilfe?

    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
quelle
4
Es ist schwer so zu sehen, aber es scheint, dass Sie bereits einige Ausgaben vor Ihrer Weiterleitung gesendet haben. Könnten Sie bitte den vollständigen Code ausdrucken und prüfen, ob kein Filter vorhanden ist?
Kartoch

Antworten:

244

Ein häufiges Missverständnis unter Startern ist, dass sie denken, dass der Aufruf von a forward(), sendRedirect()oder sendError()auf magische Weise aus dem Methodenblock austreten und "springen" würde, wodurch der Rest des Codes ignoriert wird. Beispielsweise:

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

Dies ist also eigentlich nicht wahr. Sie verhalten sich sicherlich nicht anders als alle anderen Java-Methoden ( System#exit()natürlich zu erwarten ). Wenn das someConditionobige Beispiel lautet trueund Sie daher forward()nach sendRedirect()oder sendError()auf derselben Anfrage / Antwort anrufen , ist die Wahrscheinlichkeit groß, dass Sie die Ausnahme erhalten:

java.lang.IllegalStateException: Kann nicht weitergeleitet werden, nachdem die Antwort festgeschrieben wurde

Wenn die ifAnweisung a aufruft forward()und Sie anschließend sendRedirect()oder aufrufen sendError(), wird die folgende Ausnahme ausgelöst:

java.lang.IllegalStateException: sendRedirect () kann nicht aufgerufen werden, nachdem die Antwort festgeschrieben wurde

Um dies zu beheben, müssen Sie anschließend entweder eine return;Anweisung hinzufügen

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

... oder um einen else-Block einzuführen.

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

Um die Grundursache in Ihrem Code zu ermitteln, suchen Sie einfach nach einer Zeile, die a aufruft forward(), sendRedirect()oder sendError()ohne den Methodenblock zu verlassen oder den Rest des Codes zu überspringen. Dies kann sich innerhalb desselben Servlets vor der bestimmten Codezeile befinden, aber auch in jedem Servlet oder Filter, das vor dem bestimmten Servlet aufgerufen wurde.

Im Fall sendError(), wenn Ihr einziger Zweck den Antwortstatus gesetzt ist, verwenden Sie setStatus()stattdessen.


Eine andere wahrscheinliche Ursache ist, dass das Servlet in die Antwort schreibt, während a forward()aufgerufen wird oder auf dieselbe Weise aufgerufen wurde.

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

Die Standardgröße des Antwortpuffers beträgt bei den meisten Servern standardmäßig 2 KB. Wenn Sie also mehr als 2 KB darauf schreiben, wird sie festgeschrieben und schlägt auf forward()die gleiche Weise fehl:

java.lang.IllegalStateException: Kann nicht weitergeleitet werden, nachdem die Antwort festgeschrieben wurde

Die Lösung liegt auf der Hand. Schreiben Sie einfach nicht in die Antwort im Servlet. Das liegt in der Verantwortung der JSP. Sie legen einfach ein Anforderungsattribut wie folgt fest request.setAttribute("data", "some string")und drucken es dann wie folgt in JSP aus ${data}. Auf unserer Servlets-Wiki-Seite erfahren Sie, wie Sie Servlets richtig verwenden.


Eine andere wahrscheinliche Ursache ist, dass das Servlet einen Dateidownload in die Antwort schreibt, wonach z forward(). B. a aufgerufen wird.

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

Dies ist technisch nicht möglich. Sie müssen den forward()Anruf entfernen . Der Endbenutzer bleibt auf der aktuell geöffneten Seite. Wenn Sie die Seite nach einem Dateidownload tatsächlich ändern möchten, müssen Sie die Dateidownloadlogik auf das Laden der Seite der Zielseite verschieben.


Noch eine weitere mögliche Ursache ist , dass das forward(), sendRedirect()oder sendError()Methoden werden über Java - Code eingebettet in einer JSP - Datei in Form von altmodischer Art und Weise aufgerufen <% scriptlets %>, eine Praxis , das wurde seit 2001 offiziell abgeraten . Beispielsweise:

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

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

Das Problem hierbei ist, dass JSP intern sofort Vorlagentext (dh HTML-Code) über schreibt, out.write("<!DOCTYPE html> ... etc ...")sobald er auftritt. Dies ist also im Wesentlichen das gleiche Problem wie im vorherigen Abschnitt erläutert.

Die Lösung liegt auf der Hand. Schreiben Sie einfach keinen Java-Code in eine JSP-Datei. Dies liegt in der Verantwortung einer normalen Java-Klasse wie einem Servlet oder einem Filter. Auf unserer Servlets-Wiki-Seite erfahren Sie, wie Sie Servlets richtig verwenden.


Siehe auch:


Unabhängig von Ihrem konkreten Problem verliert Ihr JDBC-Code Ressourcen. Beheben Sie das auch. Hinweise finden Sie auch unter Wie oft sollten Connection, Statement und ResultSet in JDBC geschlossen werden?

BalusC
quelle
2
Mit einer Pause meinst du break;? Das würde bedeuten, dass sich der Code in einer foroder einer whileSchleife befand, in der der Code forward()während der Schleife wiederholt aufgerufen wurde (was daher falsch ist, sollten Sie nach der Schleife nur einmal vorwärts aufrufen - oder um die Schleife zu entfernen, da sie anscheinend nicht benötigt wird). .
BalusC
@BalusC Haben Sie eine Idee zu diesem verwandten Problem? stackoverflow.com/questions/18658021/…
Confile
@confile: Ich mache kein Grails, aber basierend auf dem Aufrufstapel führt es immer noch einen forward()Anruf aus, während es das nicht tun sollte. JSF, mit dem ich vertraut bin, macht das auch, wenn Sie nicht ausdrücklich anrufen FacesContext#responseComplete(). Diese verwandte Frage (die ich mit den Schlüsselwörtern "Grails verhindern Render-Antwort" gefunden habe) kann hilfreich sein: stackoverflow.com/questions/5708654/…
BalusC
@BalusC Grails ist im Grunde Java, aber das Problem hängt mit Servlets zusammen. Haben Sie eine andere Idee, was ich tun kann? Ich habe nach jedem Rendern eine Rückgabe eingefügt, umgeleitet und weitergeleitet, wie Sie vorgeschlagen haben.
Confile
@confile: Ich weiß. Ich habe die Ursache bereits beantwortet: Grails führt immer noch einen forward()Anruf durch, während dies nicht der Fall sein sollte. Die Lösung liegt auf der Hand: Sagen Sie ihm, dass er das nicht tun soll. Es hatte nämlich keine Ahnung, dass Sie programmgesteuert den Job übernommen haben, den Grails erledigen sollte: den Umgang mit der Antwort. Technisch habe ich keine Ahnung, wie ich Grails das sagen soll. Aber ich weiß, dass viele andere MVC-Frameworks dies unterstützen (angewiesen werden, die Antwort nicht selbst zu verarbeiten), wie JSF, Spring MVC, Wicket usw. Ich wäre überrascht, wenn dies in Grails unmöglich ist.
BalusC
19

Selbst das Hinzufügen einer return-Anweisung führt zu dieser Ausnahme, für die dieser Code nur eine Lösung darstellt:

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

In der Regel wird dieser Fehler angezeigt, nachdem Sie bereits eine Umleitung durchgeführt haben und dann versuchen, weitere Daten an den Ausgabestream auszugeben. In den Fällen, in denen ich dies in der Vergangenheit gesehen habe, ist es oft einer der Filter, der versucht, die Seite umzuleiten und dann immer noch zum Servlet weiterzuleiten. Ich kann nicht sofort feststellen, dass mit dem Servlet etwas nicht stimmt. Vielleicht möchten Sie auch einen Blick auf die vorhandenen Filter werfen.

Bearbeiten : Weitere Hilfe bei der Diagnose des Problems ...

Der erste Schritt zur Diagnose dieses Problems besteht darin, genau festzustellen, wo die Ausnahme ausgelöst wird. Wir gehen davon aus, dass es von der Linie geworfen wird

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

Möglicherweise stellen Sie jedoch fest, dass es später im Code ausgelöst wird, wenn Sie versuchen, eine Ausgabe in den Ausgabestream durchzuführen, nachdem Sie versucht haben, die Weiterleitung durchzuführen. Wenn es aus der obigen Zeile kommt, bedeutet dies, dass Sie irgendwo vor dieser Zeile entweder:

  1. Daten an den Ausgabestream ausgeben oder
  2. zuvor eine weitere Weiterleitung durchgeführt.

Viel Glück!

Paul Wagland
quelle
2

Dies liegt daran, dass Ihr Servlet versucht, auf ein nicht mehr vorhandenes Anforderungsobjekt zuzugreifen. Die Forward- oder Include-Anweisung eines Servlets stoppt die Ausführung des Methodenblocks nicht. Es wird wie bei jeder anderen Java-Methode bis zum Ende des Methodenblocks oder der ersten return-Anweisung fortgesetzt.

Der beste Weg, um dieses Problem zu beheben, besteht darin, die Seite (auf der Sie die Anforderung weiterleiten möchten) dynamisch gemäß Ihrer Logik festzulegen. Das ist:

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
}

und mache den vorwärts nur einmal in der letzten Zeile ...

Sie können dieses Problem auch mithilfe der return-Anweisung nach jedem forward () beheben oder jedes forward () in den if ... else-Block einfügen

Suman Sengupta
quelle
2

Ich entfernte

        super.service(req, res);

Dann hat es bei mir gut funktioniert

kartikag01
quelle
2

Stoßen...

Ich hatte gerade den gleichen Fehler. Ich habe festgestellt, dass ich super.doPost(request, response);beim Überschreiben der doPost()Methode sowie beim expliziten Aufrufen des Konstrukts der Oberklasse aufgerufen habe

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

Sobald ich das auskommentiert habe super.doPost(request, response);doPost() Aussage von innen auskommentierte, funktionierte sie perfekt ...

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

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

}

Unnötig zu erwähnen, dass ich die super()Best Practices erneut lesen muss : p

John Rambo
quelle
1

Sie sollten return hinzufügen Anweisung , während Sie den Flow weiterleiten oder umleiten.

Beispiel:

wenn vorwärts,

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

wenn umleiten,

    response.sendRedirect(roundTripURI);
    return;
Ashish Mishra
quelle
0

Nach der Rücklaufmethode können Sie dies einfach tun:

return null;

Es wird den aktuellen Bereich brechen.

Amir Amiri
quelle