java.lang.IllegalStateException: Tidak dapat (meneruskan | sendRedirect | membuat sesi) setelah tanggapan dilakukan


96

Metode ini melempar

java.lang.IllegalStateException: Tidak dapat meneruskan setelah respons dilakukan

dan saya tidak dapat menemukan masalahnya. Ada bantuan?

    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
Sulit untuk melihat seperti ini, tetapi tampaknya Anda sudah mengirimkan beberapa keluaran sebelum Anda meneruskan. Bisakah Anda mencetak kode lengkap dan memeriksa apakah Anda tidak memiliki filter apa pun?
Kartoch

Jawaban:


244

Kesalahpahaman yang umum di antara para pemula adalah bahwa mereka berpikir bahwa panggilan a forward(), sendRedirect()atau sendError()secara ajaib akan keluar dan "melompat" keluar dari blok metode, dengan ini mengabaikan sisa kode. Sebagai contoh:

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

Jadi ini sebenarnya tidak benar. Mereka tentu tidak berperilaku berbeda dari metode Java lainnya ( System#exit()tentu saja diharapkan). Ketika contoh someConditiondi atas adalah truedan Anda dengan demikian memanggil forward()setelah sendRedirect()atau sendError()atas permintaan / tanggapan yang sama, maka kemungkinan besar Anda akan mendapatkan pengecualian:

java.lang.IllegalStateException: Tidak dapat meneruskan setelah respons dilakukan

Jika ifpernyataan memanggil a forward()dan Anda kemudian memanggil sendRedirect()atau sendError(), maka pengecualian di bawah ini akan dilontarkan:

java.lang.IllegalStateException: Tidak dapat memanggil sendRedirect () setelah respons dilakukan

Untuk memperbaikinya, Anda perlu menambahkan return;pernyataan sesudahnya

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

... atau untuk memperkenalkan blok lain.

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

Untuk menemukan akar masalah dalam kode Anda, cukup cari baris apa pun yang memanggil a forward(), sendRedirect()atau sendError()tanpa keluar dari blok metode atau melewatkan sisa kode. Ini bisa berada di dalam servlet yang sama sebelum baris kode tertentu, tetapi juga di servlet atau filter mana pun yang telah dipanggil sebelum servlet tertentu.

Dalam kasus sendError(), jika satu-satunya tujuan Anda adalah menyetel status respons, gunakan setStatus()saja.


Kemungkinan penyebab lainnya adalah servlet menulis ke respons saat a forward()akan dipanggil, atau telah dipanggil dengan metode yang sama.

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

Ukuran buffer respons secara default di sebagian besar server menjadi 2KB, jadi jika Anda menulis lebih dari 2KB padanya, maka itu akan dilakukan dan forward()akan gagal dengan cara yang sama:

java.lang.IllegalStateException: Tidak dapat meneruskan setelah respons dilakukan

Solusinya jelas, jangan menulis ke respon di servlet. Itu tanggung jawab JSP. Anda tinggal mengatur atribut permintaan seperti itu request.setAttribute("data", "some string")dan kemudian mencetaknya di JSP seperti itu ${data}. Lihat juga halaman wiki Servlets kami untuk mempelajari bagaimana menggunakan Servlets dengan cara yang benar.


Kemungkinan penyebab lainnya adalah servlet menulis file download ke respon setelah itu misalnya a forward()dipanggil.

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

Ini secara teknis tidak mungkin. Anda perlu menghapus forward()panggilan. Pengguna akhir akan tetap berada di halaman yang dibuka saat ini. Jika Anda benar-benar bermaksud untuk mengubah halaman setelah mendownload file, Anda perlu memindahkan logika download file untuk memuat halaman dari halaman target.


Namun kemungkinan penyebab lainnya adalah bahwa forward(), sendRedirect()atau sendError()metode dipanggil melalui kode Java yang disematkan dalam file JSP dalam bentuk cara lama <% scriptlets %>, sebuah praktik yang secara resmi tidak disarankan sejak 2001 . Sebagai contoh:

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

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

Masalahnya di sini adalah bahwa JSP secara internal segera menulis teks template (yaitu kode HTML) out.write("<!DOCTYPE html> ... etc ...")segera setelah ditemukan. Ini pada dasarnya adalah masalah yang sama seperti yang dijelaskan di bagian sebelumnya.

Solusinya jelas, jangan menulis kode Java di file JSP. Itu adalah tanggung jawab kelas Java normal seperti Servlet atau Filter. Lihat juga halaman wiki Servlets kami untuk mempelajari bagaimana menggunakan Servlets dengan cara yang benar.


Lihat juga:


Tidak terkait dengan masalah konkret Anda, kode JDBC Anda membocorkan sumber daya. Perbaiki itu juga. Untuk petunjuk, lihat juga Seberapa sering Connection, Statement dan ResultSet harus ditutup di JDBC?


2
Dengan istirahat, maksudmu break;? Itu berarti bahwa kode berada di dalam beberapa foratau whileloop di mana forward()dipanggil berulang kali selama loop (yang salah, Anda harus memanggil maju hanya sekali SETELAH loop --atau untuk menyingkirkan loop karena tampaknya tidak diperlukan) .
BalusC

@BalusC Apakah Anda punya ide tentang masalah terkait ini? stackoverflow.com/questions/18658021/…
confile

@ confile: Saya tidak mengerjakan Grails, tetapi berdasarkan tumpukan panggilan, ia masih melakukan forward()panggilan sementara seharusnya tidak melakukan itu. JSF, yang saya kenal, melakukan itu juga kecuali Anda secara eksplisit memanggil FacesContext#responseComplete(). Pertanyaan terkait ini (yang saya temukan menggunakan kata kunci "grails mencegah respons render") mungkin berguna: stackoverflow.com/questions/5708654/…
BalusC

@BalusC Grails pada dasarnya adalah Java, tetapi masalahnya terkait dengan Servlets. Apakah Anda punya ide lain apa yang bisa saya lakukan. Saya memberikan pengembalian setelah setiap render, mengarahkan ulang dan meneruskan seperti yang Anda sarankan.
confile

@ confile: Saya tahu. Saya sudah menjawab penyebabnya: Grails masih melakukan forward()panggilan sementara seharusnya tidak melakukan itu. Solusinya jelas secara fungsional: katakan padanya untuk tidak melakukan itu. Tidak ada gagasan bahwa Anda secara terprogram telah mengambil alih pekerjaan yang seharusnya dilakukan Grails: menangani respons. Secara teknis, saya tidak tahu bagaimana memberi tahu Grails tentang hal itu. Tetapi saya tahu bahwa banyak kerangka kerja MVC lain mendukung ini (diperintahkan untuk tidak menangani respons dengan sendirinya), seperti JSF, Spring MVC, Wicket, dll. Saya akan terkejut jika hal ini tidak mungkin dilakukan di Grails.
BalusC

19

bahkan menambahkan pernyataan return akan memunculkan pengecualian ini, yang solusinya hanya kode ini:

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

6

Biasanya Anda melihat kesalahan ini setelah Anda melakukan pengalihan dan kemudian mencoba mengeluarkan lebih banyak data ke aliran keluaran. Dalam kasus di mana saya telah melihat ini di masa lalu, sering kali salah satu filter yang mencoba mengarahkan ulang halaman, dan kemudian masih meneruskan ke servlet. Saya tidak bisa melihat ada yang salah dengan servlet, jadi Anda mungkin ingin mencoba melihat filter yang Anda miliki juga.

Sunting : Beberapa bantuan lagi dalam mendiagnosis masalah…

Langkah pertama untuk mendiagnosis masalah ini adalah memastikan secara tepat di mana pengecualian tersebut dilemparkan. Kami berasumsi bahwa itu dilemparkan oleh garis

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

Tetapi Anda mungkin menemukan bahwa itu dilemparkan nanti dalam kode, di mana Anda mencoba untuk mengeluarkan ke aliran keluaran setelah Anda mencoba melakukan penerusan. Jika itu berasal dari baris di atas, maka itu berarti bahwa di suatu tempat sebelum baris ini Anda memiliki:

  1. data keluaran ke arus keluaran, atau
  2. melakukan pengalihan lain sebelumnya.

Semoga berhasil!


2

Ini karena servlet Anda mencoba mengakses objek permintaan yang sudah tidak ada lagi .. Pernyataan forward atau include servlet tidak menghentikan eksekusi blok metode. Ini berlanjut ke akhir blok metode atau pernyataan pengembalian pertama seperti metode java lainnya.

Cara terbaik untuk mengatasi masalah ini cukup dengan mengatur halaman (di mana Anda seharusnya meneruskan permintaan) secara dinamis sesuai logika Anda. Itu adalah:

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
}

dan lakukan penyerangan hanya sekali pada baris terakhir ...

Anda juga dapat memperbaiki masalah ini menggunakan pernyataan return setelah setiap forward () atau meletakkan setiap forward () di blok if ... else


2

Saya dihapus

        super.service(req, res);

Kemudian itu bekerja dengan baik untuk saya


2

Menabrak...

Saya baru saja mengalami kesalahan yang sama. Saya perhatikan bahwa saya sedang memanggil super.doPost(request, response);saat menimpa doPost()metode serta secara eksplisit memanggil konstruktor superclass

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

Segera setelah saya mengomentari pernyataan super.doPost(request, response);dari dalam, doPost()itu bekerja dengan sempurna ...

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

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

}

Tak perlu dikatakan, saya perlu membaca kembali tentang super()praktik terbaik: p


1

Anda harus menambahkan pernyataan pengembalian saat Anda meneruskan atau mengarahkan aliran.

Contoh:

jika forwardind,

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

jika mengarahkan,

    response.sendRedirect(roundTripURI);
    return;

0

Setelah metode pengembalian ke depan, Anda cukup melakukan ini:

return null;

Ini akan merusak ruang lingkup saat ini.

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.