java.lang.IllegalStateException:在提交响应后不能(转发| sendRedirect |创建会话)

时间:2010-01-23 14:47:56

标签: servlets response illegalstateexception forward requestdispatcher

此方法抛出

  

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

8 个答案:

答案 0 :(得分:224)

初学者之间常见的误解是,他们认为forward()sendRedirect()sendError()的召唤会神奇地退出并“跳出”方法块,因此忽略代码的残余。例如:

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

因此实际上并非如此。它们的行为肯定不同于任何其他Java方法(当然是期望System#exit())。如果以上示例中的someConditiontrue,并且您在同一请求/回复后forward()sendRedirect()之后调用sendError(),那么机会就是你会得到例外:

  

java.lang.IllegalStateException:在提交响应后无法转发

如果if语句调用forward()并且您之后调用sendRedirect()sendError(),则会抛出以下异常:

  

java.lang.IllegalStateException:在提交响应后无法调用sendRedirect()

要解决此问题,您需要在之后添加return;语句

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

...或者引入一个else块。

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!
}

大多数服务器的响应缓冲区大小默认为2KB,因此如果你写入超过2KB,那么它将被提交,forward()将以相同的方式失败:

  

java.lang.IllegalStateException:在提交响应后无法转发

解决方案很明显,只是不要写入servlet中的响应。这是JSP的责任。您只需设置一个像request.setAttribute("data", "some string")这样的请求属性,然后在JSP中打印它,就像${data}一样。另请参阅our Servlets wiki page以了解如何以正确的方式使用Servlet。

另见:


你的具体问题是

无关,你的JDBC代码正在泄漏资源。修复它。有关提示,另请参阅How often should Connection, Statement and ResultSet be closed in JDBC?

答案 1 :(得分:19)

即使添加一个return语句也会出现这个异常,这个代码只有解决方案:

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

答案 2 :(得分:6)

通常,在完成重定向之后,您会看到此错误,然后尝试将更多数据输出到输出流。在我过去看过这种情况的情况下,通常是尝试重定向页面的过滤器之一,然后仍然转发到servlet。我看不出servlet的任何问题,所以你可能想看看你现有的任何过滤器。

编辑:在诊断问题方面有一些帮助...

诊断此问题的第一步是确定抛出异常的确切位置。我们假设它被行抛出

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

但是您可能会发现它稍后会在代码中抛出,您尝试在转发之后尝试输出到输出流。如果它来自上面一行,则意味着在此行之前的某处你有:

  1. 将数据输出到输出流,或
  2. 事先做了另一次重定向。
  3. 祝你好运!

答案 3 :(得分:2)

这是因为您的servlet正在尝试访问不再存在的请求对象。 servlet的forward或include语句不会停止方法块的执行。它像任何其他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
}

并且在最后一行只进行一次...

你也可以在每个forward()之后使用return语句解决这个问题,或者将每个forward()放在if ... else块

答案 4 :(得分:2)

我删除了

        super.service(req, res);

然后它对我来说很好

答案 5 :(得分:2)

...凹凸

我遇到了同样的错误。我注意到在覆盖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

答案 6 :(得分:0)

在转发或重定向流时,您应该添加 return 语句。

示例:

如果是forwardind,

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

如果重定向,

    response.sendRedirect(roundTripURI);
    return;

答案 7 :(得分:0)

在返回前进方法后,您可以简单地执行此操作:

return null;

它将打破目前的范围。