java.lang.IllegalStateException: Yanıt işlendikten sonra (iletme | sendRedirect | oturum oluşturulamaz)


96

Bu yöntem atar

java.lang.IllegalStateException: Yanıt işlendikten sonra iletilemez

ve sorunu tespit edemiyorum. Herhangi bir yardım?

    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
Bunu görmek zor, ancak ilerlemeden önce zaten bazı çıktılar göndermişsiniz gibi görünüyor. Lütfen tam kodu yazdırıp yerinde filtreniz olup olmadığını kontrol eder misiniz?
Kartoch

Yanıtlar:


245

Yeni başlayanlar arasında yaygın bir yanlış anlama , kodun kalıntısını görmezden gelerek, a forward(), sendRedirect()veya sendError()sihirli bir şekilde yöntem bloğundan çıkıp "atlayacağını" düşünmeleridir . Örneğin:

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

Dolayısıyla bu aslında doğru değil. Kesinlikle diğer Java yöntemlerinden farklı davranmazlar System#exit()(elbette bekleyin). Ne zaman someConditionyukarıdaki örnekte olduğu trueve böylece aradığınız forward()sonra sendRedirect()veya sendError()aynı istek / yanıt üzerine, daha sonra şans büyük sen istisna alacak:

java.lang.IllegalStateException: Yanıt işlendikten sonra iletilemez

İfade ifa'yı çağırırsa forward()ve daha sonra sendRedirect()veya çağırırsanız sendError(), aşağıdaki istisna atılır:

java.lang.IllegalStateException: Yanıt tamamlandıktan sonra sendRedirect () çağrılamaz

Bunu düzeltmek için return;daha sonra bir ifade eklemeniz gerekir

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

... veya başka bir bloğu tanıtmak için.

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

Kodunuzdaki asıl nedenini naildown için, sadece bir çağıran herhangi bir hat için arama forward(), sendRedirect()ya da sendError()yöntem blok çıkmadan veya kod kalıntısı atlamadan. Bu, belirli bir kod satırından önce aynı sunucu uygulamasının içinde olabileceği gibi, belirli sunucu uygulamasından önce çağrılan herhangi bir sunucu uygulamacığı veya filtrede de olabilir.

Durumunda sendError()sizin tek amacı yanıt durumunu ayarlamak için ise, kullanmak setStatus()yerine.


Diğer bir olası neden, sunucu uygulamasının yanıta, a forward()çağrılırken veya aynı yöntemle çağrılırken yazmasıdır .

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

Yanıt arabelleği boyutu çoğu sunucudaki varsayılan olarak 2 KB'dir, bu nedenle, 2 KB'tan fazla yazarsanız, o zaman işlenecek ve forward()aynı şekilde başarısız olacaktır:

java.lang.IllegalStateException: Yanıt işlendikten sonra iletilemez

Çözüm açıktır, sadece sunucu uygulamasındaki yanıta yazmayın. JSP'nin sorumluluğu budur. Sadece böyle bir istek niteliği belirlersiniz request.setAttribute("data", "some string")ve ardından bunu JSP'de olduğu gibi yazdırırsınız ${data}. Servlet'leri doğru şekilde nasıl kullanacağınızı öğrenmek için Servletler wiki sayfamıza da bakın .


Diğer bir olası neden, sunucu uygulamasının yanıta bir dosya indirmesi yazmasıdır ve ardından örneğin a forward()çağrılır.

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

Bu teknik olarak mümkün değil. forward()Aramayı kaldırmanız gerekiyor . Son kullanıcı o anda açık olan sayfada kalacaktır. Bir dosya indirdikten sonra sayfayı gerçekten değiştirmeyi düşünüyorsanız, dosya indirme mantığını hedef sayfanın sayfa yüklemesine taşımanız gerekir.


Yine bir başka olası neden forward(), sendRedirect()veya sendError()yöntemlerinin, 2001'den beri resmi olarak tavsiye edilmeyen<% scriptlets %> bir uygulama olan eski moda bir şekilde bir JSP dosyasına gömülü Java kodu aracılığıyla çağrılmasıdır . Örneğin:

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

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

Buradaki sorun, JSP'nin, karşılaşıldığı anda dahili olarak şablon metni (yani HTML kodu) aracılığıyla hemen yazmasıdır out.write("<!DOCTYPE html> ... etc ..."). Bu nedenle, önceki bölümde açıklananla esasen aynı problemdir.

Çözüm açıktır, sadece Java kodunu bir JSP dosyasına yazmayın. Bu, Servlet veya Filter gibi normal bir Java sınıfının sorumluluğudur. Servlet'leri doğru şekilde nasıl kullanacağınızı öğrenmek için Servletler wiki sayfamıza da bakın .


Ayrıca bakınız:


Somut sorununuzdan bağımsız olarak, JDBC kodunuz kaynakları sızdırıyor. Bunu da düzelt. İpuçları için ayrıca JDBC'de Connection, Statement ve ResultSet ne sıklıkla kapatılmalıdır?


2
Bir ara ile mi demek istiyorsun break;? Bu kod bazı içindeydi olduğu anlamına geleceğini forya whileburada döngü forward()döngü sırasında defalarca çağrıldı (böylece yanlış olan sen döngü SONRA yalnızca bir kez ileriye çağırmalıdır OR görünüşe göre gerekli değil gibi döngü kurtulmak için) .
BalusC

@BalusC Bu sorunla ilgili bir fikriniz var mı? stackoverflow.com/questions/18658021/…
2013

@confile: Grails yapmıyorum, ancak çağrı yığınına göre, forward()bunu yapmaması gerekirken hala bir çağrı yapıyor. Benim aşina olduğum JSF, açıkça çağırmadığınız sürece bunu da yapıyor FacesContext#responseComplete(). Bu ilgili soru ("grails render yanıtını engelliyor" anahtar kelimelerini kullanarak bulduğum) yardımcı olabilir: stackoverflow.com/questions/5708654/…
BalusC

@BalusC Grails temelde Java'dır, ancak sorun Servlet'lerle ilgilidir. Ne yapabileceğime dair başka bir fikrin var mı? Her render, yönlendirme ve önerdiğiniz gibi iletmeden sonra bir dönüş koydum.
2013

@confile: Biliyorum. Nedeni zaten yanıtladım: Grails, forward()bunu yapmaması gerekirken hala bir arama yapıyor. Çözüm işlevsel olarak açıktır: ona bunu yapmamasını söyleyin. Grails'in yapması gereken işi programatik olarak devraldığınız hakkında hiçbir fikriniz yoktu: yanıtı ele almak. Teknik olarak, Grails'e bunu nasıl söyleyeceğimi bilmiyorum. Ancak JSF, Spring MVC, Wicket, vb. Gibi diğer pek çok MVC çerçevesinin bunu desteklediğini biliyorum (yanıtı tek başına ele almama talimatı verildi). Grails'de bu imkansızsa şaşırırdım.
BalusC

19

Bir return ifadesi eklemek bile bu istisnayı ortaya çıkarır, bunun için tek çözüm bu koddur:

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

6

Genellikle bir yeniden yönlendirme yaptıktan sonra bu hatayı görürsünüz ve ardından çıkış akışına biraz daha fazla veri göndermeye çalışırsınız. Bunu geçmişte gördüğüm durumlarda, genellikle sayfayı yeniden yönlendirmeye çalışan filtrelerden biridir ve daha sonra yine de sunucu uygulamasına iletilir. Sunucu uygulamasında hemen yanlış bir şey göremiyorum, bu nedenle, sahip olduğunuz filtrelere de bir göz atmayı deneyebilirsiniz.

Düzenleme : Sorunu teşhis etmede biraz daha yardım ...

Bu sorunu teşhis etmenin ilk adımı, istisnanın tam olarak nereye atıldığını tespit etmektir. Hat tarafından atıldığını varsayıyoruz

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

Ancak, ilerlemeyi yapmayı denedikten sonra çıkış akışına çıktı vermeye çalıştığınız kodda daha sonra atıldığını görebilirsiniz. Yukarıdaki satırdan geliyorsa, bu satırdan önce bir yerde şunlardan birine sahip olduğunuz anlamına gelir:

  1. çıktı akışına veri çıkışı veya
  2. önceden başka bir yönlendirme yaptı.

İyi şanslar!


2

Bunun nedeni, sunucu uygulamanızın artık var olmayan bir istek nesnesine erişmeye çalışmasıdır. Bir sunucu uygulamasının forward veya include ifadesi, yöntem bloğunun yürütülmesini durdurmaz. Diğer herhangi bir java yöntemi gibi, yöntem bloğunun veya ilk dönüş ifadesinin sonuna kadar devam eder.

Bu sorunu çözmenin en iyi yolu, mantığınıza göre sayfayı (isteği iletmeyi düşündüğünüz yer) dinamik olarak ayarlayın. Yani:

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
}

ve son satırda yalnızca bir kez ileri sarın ...

bu sorunu her iletiden sonra return ifadesini kullanarak () veya if ... else bloğuna her bir ileri () koyabilirsiniz.


2

Kaldırdım

        super.service(req, res);

Sonra benim için iyi çalıştı


2

Çarpmak...

Ben de aynı hatayı aldım. Yöntemi super.doPost(request, response);geçersiz doPost()kılarken ve ayrıca süper sınıf yapıcısını açıkça çağırırken çağırdığımı fark ettim

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

Ben dışarı yorumladı kısa sürede super.doPost(request, response);içinden doPost()açıklamaya mükemmel çalıştı ...

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

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

}

Söylemeye gerek yok, super()en iyi uygulamaları yeniden okumam gerekiyor : p


1

Akışı iletirken veya yeniden yönlendirirken return ifadesi eklemelisiniz .

Misal:

ileri sürülürse,

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

yeniden yönlendiriliyorsa

    response.sendRedirect(roundTripURI);
    return;

0

İleri geri dönüş yönteminden sonra şunu yapabilirsiniz:

return null;

Mevcut kapsamı bozacak.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.