java.lang.IlegalStateException: لا يمكن (إلى الأمام | sendRedirect | إنشاء جلسة) بعد ارتكاب الاستجابة

StackOverflow https://stackoverflow.com/questions/2123514

سؤال

هذه الطريقة ترمي

java.lang.IlegalStateException: لا يمكن التوجيه بعد ارتكاب الاستجابة

وأنا غير قادر على اكتشاف المشكلة. أي مساعدة؟

    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);
    }
هل كانت مفيدة؟

المحلول

سوء فهم شائع بين المبتدئين هو أنهم يعتقدون أن نداء أ forward(), sendRedirect(), ، أو sendError() سوف يخرج سحريًا و "قفز" من كتلة الطريقة ، وتجاهل بقايا الكود. علي سبيل المثال:

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

هذا هو في الواقع غير صحيح. إنهم بالتأكيد لا يتصرفون بشكل مختلف عن أي أساليب Java أخرى (توقع من System#exit() بالتاكيد). عندما someCondition في مثال أعلاه هو true وهكذا تتصل forward() بعد sendRedirect() أو sendError() على نفس الطلب/الاستجابة ، فإن الفرصة هي كبير ستحصل على الاستثناء:

java.lang.IlegalStateException: لا يمكن التوجيه بعد ارتكاب الاستجابة

إذا if يدعو البيان أ forward() وأنت تدعو بعد ذلك sendRedirect() أو sendError(), ، ثم سيتم طرح الاستثناء أدناه:

java.lang.IlegalStateException: لا يمكن استدعاء sendRedirect () بعد ارتكاب الاستجابة

لإصلاح هذا ، تحتاج إما لإضافة ملف return; بيان بعد ذلك

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

... أو لتقديم كتلة أخرى.

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

لتركيب السبب الجذري في الكود الخاص بك ، ما عليك سوى البحث عن أي سطر يدعو أ forward(), sendRedirect() أو sendError() دون الخروج من كتلة الطريقة أو تخطي بقايا الكود. يمكن أن يكون هذا داخل نفس Servlet قبل خط الكود المعين ، ولكن أيضًا في أي servlet أو مرشح تم استدعاؤه قبل servlet معين.

في حالة sendError(), ، إذا كان الغرض الوحيد الخاص بك هو تعيين حالة الاستجابة ، فاستخدم setStatus() في حين أن.


سبب محتمل آخر هو أن Servlet يكتب إلى الاستجابة بينما أ forward() سيتم استدعاؤه ، أو تم استدعاؤه في نفس الطريقة.

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

يتخلف حجم المخزن المؤقت للمخزن المؤقت في معظم الخادم إلى 2 كيلو بايت ، لذلك إذا كتبت أكثر من 2 كيلو بايت ، فسيتم ارتكابها و forward() سوف تفشل بنفس الطريقة:

java.lang.IlegalStateException: لا يمكن التوجيه بعد ارتكاب الاستجابة

الحل واضح ، فقط لا تكتب إلى الرد في servlet. هذه هي مسؤولية JSP. يمكنك فقط تعيين سمة طلب مثل ذلك request.setAttribute("data", "some string") ثم طباعته في JSP مثل ذلك ${data}. أنظر أيضا صفحة servlets wiki لدينا لمعرفة كيفية استخدام servlets بالطريقة الصحيحة.


سبب محتمل آخر هو أن forward(), sendRedirect() أو sendError() يتم استدعاء الطرق عبر كود Java مضمن في ملف JSP في شكل من الطراز القديم <% scriptlets %>, ، وهي ممارسة كانت تم إحباطه رسميًا منذ عام 2001. علي سبيل المثال:

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

        <% sendRedirect(); %>

        ...
    </body>
</html>

المشكلة هنا هي أن JSP يكتب على الفور نص القالب (أي رمز HTML) عبر out.write("<!DOCTYPE html> ... etc ...") بمجرد مواجهتها. وبالتالي فإن هذا هو نفس المشكلة كما هو موضح في القسم السابق.

الحل واضح ، فقط لا تكتب رمز Java في ملف JSP. هذه هي مسؤولية فئة Java العادية مثل servlet أو مرشح. أنظر أيضا صفحة servlets wiki لدينا لمعرفة كيفية استخدام servlets بالطريقة الصحيحة.


أنظر أيضا:


غير مرتبطه لمشكلتك الملموسة ، فإن رمز JDBC الخاص بك هو تسرب الموارد. إصلاح ذلك كذلك. للحصول على تلميحات ، انظر أيضًا كم مرة يجب إغلاق الاتصال والبيان ونتائجها في JDBC؟

نصائح أخرى

حتى إضافة عبارة إرجاع يثير هذا الاستثناء ، وهو الحل الوحيد هو هذا الرمز:

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

عادةً ما ترى هذا الخطأ بعد أن قمت بالفعل بإعادة التوجيه ثم حاول إخراج المزيد من البيانات إلى دفق الإخراج. في الحالات التي رأيت فيها هذا في الماضي ، غالبًا ما يكون أحد المرشحات التي تحاول إعادة توجيه الصفحة ، ثم لا تزال تتقدم إلى Servlet. لا يمكنني رؤية أي شيء خاطئ على الفور في Servlet ، لذلك قد ترغب في محاولة إلقاء نظرة على أي مرشحات لديك أيضًا.

تعديل: المزيد من المساعدة في تشخيص المشكلة ...

تتمثل الخطوة الأولى لتشخيص هذه المشكلة في التأكد بالضبط من أين يتم طرح الاستثناء. نحن نفترض أنه يتم إلقاؤه بواسطة الخط

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

ولكن قد تجد أنه يتم إلقاؤه لاحقًا في الكود ، حيث تحاول الإخراج إلى دفق الإخراج بعد أن حاولت القيام بالأمام. إذا كان قادمًا من السطر أعلاه ، فهذا يعني أنه في مكان ما قبل هذا الخط ، لديك أيضًا:

  1. إخراج بيانات دفق الإخراج ، أو
  2. القيام آخر إعادة التوجيه مسبقا.

حظا طيبا وفقك الله!

وذلك لأن servlet تحاول الوصول إلى كائن طلب لم يعد موجودًا .. لا يتوقف إعادة تشغيل Servlet أو تضمينه عن تنفيذ كتلة الطريقة. يستمر حتى نهاية كتلة الطريقة أو بيان الإرجاع الأول تمامًا مثل أي طريقة أخرى من Java.

أفضل طريقة لحل هذه المشكلة ، ما عليك سوى تعيين الصفحة (حيث تفترض أن توجيه الطلب) بشكل ديناميكي وفقًا لمنطقك. إنه:

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
}

وقم بالأمام مرة واحدة فقط في السطر الأخير ...

يمكنك أيضًا إصلاح هذه المشكلة باستخدام عبارة الإرجاع بعد كل متابعة () أو وضع كل مرة أخرى () إذا ... كتلة أخرى

ازلت

        super.service(req, res);

ثم عملت بشكل جيد بالنسبة لي

صدم...

كان لدي نفس الخطأ. لقد لاحظت أنني كنت أذكر super.doPost(request, response); عند تجاوز doPost() الطريقة وكذلك الاحتجاج بشكل صريح من مُنشئ الفئة الفائقة

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

بمجرد أن علقت super.doPost(request, response); من داخل doPost() بيان أنه عمل بشكل مثالي ...

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

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

}

وغني عن القول ، أنا بحاجة إلى إعادة قراءة super() أفضل الممارسات: P

يجب أن تضيف إرجاع بيان أثناء إعادة توجيه التدفق أو إعادة توجيهه.

مثال:

إذا كنت إلى الأمام ،

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

في حالة إعادة التوجيه ،

    response.sendRedirect(roundTripURI);
    return;

بعد العودة إلى الأمام ، يمكنك ببساطة القيام بذلك:

return null;

سوف يكسر النطاق الحالي.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top