java.lang.IllegalStateException:応答がコミットされた後は(転送| sendRedirect |セッションを作成)できません


96

このメソッドはスローします

java.lang.IllegalStateException:応答がコミットされた後は転送できません

そして、私は問題を見つけることができません。何か助け?

    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);
    }

4
このように見るのは難しいですが、転送する前にすでにいくつかの出力を送信しているようです。完全なコードを印刷して、フィルタが設定されていないかどうか確認してください。
Kartoch、2010年

回答:


244

先発の間で共通の誤解は、彼らがの呼び出しと思うということであるforward()sendRedirect()またはsendError()魔法の終了とメソッドのブロックのうち、「ジャンプ」、ここにコードの残りを無視します。例えば:

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

したがって、これは実際には当てはまりません。もちろん、他のJavaメソッドと動作が異なることはありません(System#exit()当然です)。場合はsomeCondition、上記の例ではtrue、あなたは、このように呼んでいるforward()の後sendRedirect()sendError()、同じ要求/応答には、チャンスがある、大きなあなたが例外を取得すること:

java.lang.IllegalStateException:応答がコミットされた後は転送できません

場合ifステートメントが呼び出すforward()と、あなたはその後呼んでいるsendRedirect()sendError()、例外の下にスローされます。

java.lang.IllegalStateException:応答がコミットされた後はsendRedirect()を呼び出せません

これを修正するには、return;後でステートメントを追加する必要があります

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

...または、elseブロックを導入します。

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

コードの根本原因を特定するには、メソッドブロックを終了したり、コードの残りをスキップしたりせずにforward()、を呼び出す行を検索します。これは、特定のコード行の前の同じサーブレット内にある場合がありますが、特定のサーブレットの前に呼び出されたサーブレットまたはフィルター内にある場合もあります。sendRedirect()sendError()

sendError()場合、唯一の目的が応答ステータスの設定である場合は、setStatus()代わりに使用してください。


もう1つの考えられる原因は、forward()が呼び出されるか、まったく同じメソッドで呼び出されている間に、サーブレットが応答に書き込むことです。

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

ほとんどのサーバーでは、応答バッファーのサイズはデフォルトで2KBに設定されているため、2KBを超える値を書き込んだ場合、コミットforward()され、同じように失敗します。

java.lang.IllegalStateException:応答がコミットされた後は転送できません

解決策は明白ですが、サーブレットの応答には書き込まないでください。それはJSPの責任です。このようにリクエスト属性を設定request.setAttribute("data", "some string")し、JSPでそれを印刷するだけ${data}です。サーブレットを正しい方法で使用する方法については、サーブレットのWikiページも参照してください。


別の考えられる原因は、サーブレットが応答にファイルのダウンロードを書き込んだ後、たとえばa forward()が呼び出されたことです。

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

これは技術的に不可能です。forward()通話を削除する必要があります。エンドユーザーは現在開いているページにとどまります。ファイルのダウンロード後に実際にページを変更する場合は、ファイルのダウンロードロジックをターゲットページのページロードに移動する必要があります。


さらに別の考えられる原因はforward()sendRedirect()またはsendError()メソッドが<% scriptlets %>、旧式の方法でJSPファイルに埋め込まれたJavaコードを介して呼び出されることです。これは、2001年以降公式には推奨されていません。例えば:

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

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

ここでの問題は、JSPが発生するとすぐに、内部的に直ちにテンプレートテキスト(HTMLコード)を書き込むout.write("<!DOCTYPE html> ... etc ...")ことです。したがって、これは前のセクションで説明したのと本質的に同じ問題です。

解決策は明らかです。JSPファイルにJavaコードを記述しないでください。これは、サーブレットやフィルターなどの通常のJavaクラスの責任です。サーブレットを正しい方法で使用する方法については、サーブレットのWikiページも参照してください。


以下も参照してください。


具体的な問題とは無関係に、JDBCコードがリソースをリークしています。それも修正します。ヒントについては、JDBCでConnection、Statement、およびResultSetを閉じる頻度を参照してください


2
休憩とはどういう意味break;ですか?これは、コードはいくつかの内部できたことを意味するforか、while前記ループforward()ループの中に繰り返し呼ばれていました(これ間違っていた、あなたはループの後に一度だけ前方に呼び出す必要があり、-OR、それが明らかに必要ではないですように、ループを取り除くために) 。
BalusC 2010年

@BalusCこの関連する問題についてアイデアがありますか?stackoverflow.com/questions/18658021/...
confile

@confile:私はGrailsをしていませんが、コールスタックに基づいて、それはforward()すべきではないのにまだコールを実行しています。私がよく知っているJSFは、明示的にを呼び出さない限り、これも行いますFacesContext#responseComplete()。役立つかもしれない(私は「Grailsのレスポンスをレンダリング防ぐ」のキーワードを使用しています)、この関連の質問:stackoverflow.com/questions/5708654/...
BalusC

@BalusC Grailsは基本的にJavaですが、問題はサーブレットに関連しています。私にできることは他にありますか?私はあなたが提案したように、各レンダリング、リダイレクト、転送の後にリターンを入れます。
confile

@confile:わかっています。私はすでに原因に答えています:Grailsはまだforward()コールを実行しているはずですが、それを行うべきではありません。解決策は機能的に明白です。それを行わないように伝えます。つまり、Grailsが行うはずだった仕事をプログラムで引き継いだという考えはありませんでした。それは、応答の処理です。技術的には、Grailsにどのように伝えるかわかりません。しかし、JSF、Spring MVC、Wicketなど、他の多くのMVCフレームワークがこれをサポートしている(それ自体は応答を処理しないように指示されている)ことを知っています。Grailsでこれが不可能な場合は、驚きます。
BalusC 2013

19

returnステートメントを追加するだけでもこの例外が発生します。解決策はこのコードのみです。

if(!response.isCommitted())
// Place another redirection

6

通常、このエラーは、リダイレクトを既に実行してから、出力ストリームにさらにデータを出力しようとしたときに発生します。これを以前に見た場合、多くの場合、ページのリダイレクトを試み、その後サーブレットに転送しようとするフィルターの1つです。サーブレットですぐに問題が発生することはないので、配置しているフィルタも確認してみてください。

編集:問題の診断に役立つヘルプ…

この問題を診断する最初のステップは、例外がスローされている場所を正確に確認することです。私たちはそれがラインによって投げられていると仮定しています

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

しかし、それがコードの後半でスローされて、転送を試みた後に出力ストリームに出力しようとしていることに気付く場合があります。上記の行からのものである場合、それはこの行の前のどこかにあることを意味します:

  1. 出力ストリームへのデータの出力、または
  2. 事前に別のリダイレクトを行いました。

幸運を!


2

これは、サーブレットが存在しないリクエストオブジェクトにアクセスしようとしているためです。サーブレットのforwardまたはincludeステートメントは、メソッドブロックの実行を停止しません。他のJavaメソッドと同じように、メソッドブロックまたは最初のreturnステートメントの最後まで続きます。

この問題を解決する最良の方法は、ロジックに従ってページ(リクエストを転送することを想定しているページ)を動的に設定するだけです。あれは:

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
}

最後の行で1回だけ転送を行います...

また、各forward()の後にreturnステートメントを使用してこの問題を修正するか、if ... elseブロックに各forward()を配置することもできます


2

私は削除しました

        super.service(req, res);

その後、それは私のためにうまくいきました


2

バンプ...

同じエラーが発生しました。メソッドをsuper.doPost(request, response);オーバーライドするときdoPost()、およびスーパークラスコンストラクターを明示的に呼び出すときに呼び出していることに気付きました

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

super.doPost(request, response);from within doPost()ステートメントをコメントアウトするとすぐに、完全に機能しました...

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

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

}

言うまでもなく、super()ベストプラクティスをもう一度読む必要があります:p


1

フローを転送またはリダイレクトしているときにreturnステートメントを追加する必要があります。

例:

forwardindの場合、

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

リダイレクトする場合、

    response.sendRedirect(roundTripURI);
    return;

0

return forwardメソッドの後、あなたはこれを簡単に行うことができます:

return null;

現在のスコープを壊します。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.