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

发布于 2024-08-18 12:36:05 字数 2732 浏览 8 评论 0 原文

这个方法抛出

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

This method throws

java.lang.IllegalStateException: Cannot forward after response has been committed

and I am unable to spot the problem. Any help?

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(9

慢慢从新开始 2024-08-25 12:36:06

forward/sendRedirect/sendError 不要退出该方法!

初学者中一个常见的误解是,他们认为调用 forward()sendRedirect()sendError() 方法会神奇地退出并“跳”出方法块,从而忽略代码的剩余部分。例如在 servlet 中:

protected void doXxx(...) {
    if (someCondition) {
        response.sendRedirect(...);
    }

    dispatcher.forward(...); // This is STILL invoked when someCondition is true!
}

或者在过滤器中:

public void doFilter(...) {
    if (someCondition) {
        response.sendRedirect(...);
    }

    chain.doFilter(...); // This is STILL invoked when someCondition is true!
}

因此这实际上是不正确的。它们的行为当然与任何其他 Java 方法没有什么不同(当然,System#exit() 除外)。当上例中的 someConditiontrue 并且您因此在之后调用 forward()doFilter()在同一个请求/响应上使用 sendRedirect()sendError() ,那么您收到异常的机会就

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

这也适用于相反的条件。如果 if 语句调用 forward() 并且您随后调用 sendRedirect()sendError() ,那么可以抛出以下异常:

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

要解决此问题,您需要随后添加一个 return; 语句

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

    dispatcher.forward(...);
}

...或引入一个 else 块。

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

要确定代码中的根本原因,只需搜索调用 forward()sendRedirect()sendError() 的任何行,而无需退出方法块或跳过代码的剩余部分。这可以位于特定代码行之前的同一 servlet 内,也可以位于在特定 servlet 之前调用的任何 servlet 或过滤器中。

对于 sendError(),如果您的唯一目的是设置响应状态,请改用 setStatus()

不要在 forward/sendRedirect/sendError 之前写入任何字符串

另一个可能的原因是 servlet 在 forward( ) 将被调用,或者已经在相同的方法中被调用。

protected void doXxx() {
    out.write("<p>some html</p>");

    // ...

    dispatcher.forward(); // Fail!
}

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

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

解决方案很明显,只需不要将 HTML 块写入 servlet 中的响应即可。这是 JSP 的职责。您只需设置一个请求属性,如 request.setAttribute("data", "some string") ,然后在 JSP 中打印它,如 ${data} 。另请参阅我们的 Servlet wiki 页面,了解如何正确使用 Servlet。

forward/sendRedirect/sendError 之前不要写入任何文件

另一个可能的原因是 servlet 将文件下载写入响应,之后例如调用forward()

protected void doXxx() {
    out.write(bytes);

    // ...
 
    dispatcher.forward(); // Fail!
}

这在技术上是不可能的。您需要删除 forward() 调用。最终用户将停留在当前打开的页面上。如果您确实打算在文件下载后更改页面,那么最好的选择是将 cookie 添加到响应中,并在由下载链接/按钮触发的 JavaScript 片段中轮询它。另请参阅 如何在生成后发送重定向在 Servlet 中生成文件下载

另一种方法是将文件下载逻辑移至目标页面的页面加载。基本上:首先使用此答案中提到的方式在磁盘上创建一个临时文件 如何在基于 servlet 的 Web 应用程序中临时保存生成的文件,然后使用文件名/标识符作为请求参数发送重定向,并在目标页面中根据条件进行打印该请求参数的存在 会立即通过此答案中提到的方式之一下载临时文件 最简单的方法在 Java Web 应用程序中提供来自应用程序服务器外部的静态数据

不要在 JSP 中调用 forward/sendRedirect/sendError

另一个可能的原因是 forward(), < code>sendRedirect() 或 sendError() 方法通过嵌入在 JSP 文件中的 Java 代码以老式方式 <% scriptlets %> 的形式调用>,这种做法自 2003 年起就被官方禁止。例如:

<!DOCTYPE html>
<html lang="en">
    <head>
        ... 
    </head>
    <body>
        ...
        <% response.sendRedirect(...); %>
        ...
    </body>
</html>

这里的问题是 JSP 内部立即通过 out.write(" ... etc ...") 写入模板文本(即 HTML 代码)是遇到了。因此,这本质上是与上一节中解释的问题相同的问题。

解决方案很明显,只要不要在 JSP 文件中编写 Java 代码即可。这是普通 Java 类(例如 Servlet 或 Filter)的职责。另请参阅我们的 Servlet wiki 页面,了解如何正确使用 Servlet。

另请参阅:


与您的具体问题无关,您的 JDBC 代码正在泄漏资源。也解决这个问题。有关提示,另请参阅连接的频率、Statement 和 ResultSet 在 JDBC 中要关闭吗?

forward/sendRedirect/sendError do NOT exit the method!

A common misunderstanding among starters is that they think that the call of a forward(), sendRedirect(), or sendError() method would magically exit and "jump" out of the method block, hereby ignoring the remnant of the code. For example in a servlet:

protected void doXxx(...) {
    if (someCondition) {
        response.sendRedirect(...);
    }

    dispatcher.forward(...); // This is STILL invoked when someCondition is true!
}

Or in a filter:

public void doFilter(...) {
    if (someCondition) {
        response.sendRedirect(...);
    }

    chain.doFilter(...); // This is STILL invoked when someCondition is true!
}

This is thus actually not true. They do certainly not behave differently than any other Java methods (expect of System#exit() of course). When the someCondition in above example is true and you're thus calling forward() or doFilter() after sendRedirect() or sendError() on the same request/response, then the chance is big that you will get the exception:

java.lang.IllegalStateException: Cannot forward after response has been committed

This also applies to the inverse condition. If the if statement calls a forward() and you're afterwards calling sendRedirect() or sendError(), then below exception can be thrown:

java.lang.IllegalStateException: Cannot call sendRedirect() after the response has been committed

To fix this, you need either to add a return; statement afterwards

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

    dispatcher.forward(...);
}

... or to introduce an else block.

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

To naildown the root cause in your code, just search for any line which calls a forward(), sendRedirect() or sendError() without exiting the method block or skipping the remnant of the code. This can be inside the same servlet before the particular code line, but also in any servlet or filter which was been called before the particular servlet.

In case of sendError(), if your sole purpose is to set the response status, use setStatus() instead.

Do not write any string before forward/sendRedirect/sendError

Another probable cause is that the servlet writes to the response while a forward() will be called, or has been called in the very same method.

protected void doXxx() {
    out.write("<p>some html</p>");

    // ...

    dispatcher.forward(); // Fail!
}

The response buffer size defaults in most server to 2KB, so if you write more than 2KB to it, then it will be committed and forward() will fail the same way:

java.lang.IllegalStateException: Cannot forward after response has been committed

Solution is obvious, just don't write chunks of HTML to the response in the servlet. That's the responsibility of the JSP. You just set a request attribute like so request.setAttribute("data", "some string") and then print it in JSP like so ${data}. See also our Servlets wiki page to learn how to use Servlets the right way.

Do not write any file before forward/sendRedirect/sendError

Another probable cause is that the servlet writes a file download to the response after which e.g. a forward() is called.

protected void doXxx() {
    out.write(bytes);

    // ...
 
    dispatcher.forward(); // Fail!
}

This is technically not possible. You need to remove the forward() call. The enduser will stay on the currently opened page. If you actually intend to change the page after a file download, then your best bet is to add a cookie to the response and poll for it in a piece of JavaScript which is triggered by the download link/button. See also How to send a redirect after generating a file download in Servlet.

The alternative is to move the file download logic to page load of the target page. Basically: first create a temporary file on disk using the way mentioned in this answer How to save generated file temporarily in servlet based web application, then send a redirect with the file name/identifier as request param, and in the target page conditionally print based on the presence of that request param a <script>window.location='...';</script> which immediately downloads the temporary file via one of the ways mentioned in this answer Simplest way to serve static data from outside the application server in a Java web application.

Do not call forward/sendRedirect/sendError in JSP

Yet another probable cause is that the forward(), sendRedirect() or sendError() methods are invoked via Java code embedded in a JSP file in form of old fashioned way <% scriptlets %>, a practice which was officially discouraged since 2003. For example:

<!DOCTYPE html>
<html lang="en">
    <head>
        ... 
    </head>
    <body>
        ...
        <% response.sendRedirect(...); %>
        ...
    </body>
</html>

The problem here is that JSP internally immediately writes template text (i.e. HTML code) via out.write("<!DOCTYPE html> ... etc ...") as soon as it's encountered. This is thus essentially the same problem as explained in previous section.

Solution is obvious, just don't write Java code in a JSP file. That's the responsibility of a normal Java class such as a Servlet or a Filter. See also our Servlets wiki page to learn how to use Servlets the right way.

See also:


Unrelated to your concrete problem, your JDBC code is leaking resources. Fix that as well. For hints, see also How often should Connection, Statement and ResultSet be closed in JDBC?

感情废物 2024-08-25 12:36:06

即使添加 return 语句也会引发此异常,唯一的解决方案是以下代码:

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

even adding a return statement brings up this exception, for which only solution is this code:

if(!response.isCommitted())
// Place another redirection
蹲墙角沉默 2024-08-25 12:36:06

通常,您在完成重定向后会看到此错误,然后尝试将更多数据输出到输出流。在我过去看到过这种情况的情况下,通常是过滤器之一尝试重定向页面,然后仍然转发到 servlet。我无法立即发现 servlet 存在任何问题,因此您可能还想尝试查看您已安装的任何过滤器。

编辑:诊断问题的更多帮助...

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

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

,但是您可能会发现它是在代码中稍后抛出的,在您尝试执行转发之后,您试图输出到输出流。如果它来自上面的行,那么这意味着在该行之前的某个地方您有:

  1. 将数据输出到输出流,或者
  2. 事先完成另一个重定向。

祝你好运!

Typically you see this error after you have already done a redirect and then try to output some more data to the output stream. In the cases where I have seen this in the past, it is often one of the filters that is trying to redirect the page, and then still forwards through to the servlet. I cannot see anything immediately wrong with the servlet, so you might want to try having a look at any filters that you have in place as well.

Edit: Some more help in diagnosing the problem…

The first step to diagnosing this problem is to ascertain exactly where the exception is being thrown. We are assuming that it is being thrown by the line

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

But you might find that it is being thrown later in the code, where you are trying to output to the output stream after you have tried to do the forward. If it is coming from the above line, then it means that somewhere before this line you have either:

  1. output data to the output stream, or
  2. done another redirect beforehand.

Good luck!

与风相奔跑 2024-08-25 12:36:06

碰撞...

我刚刚遇到了同样的错误。我注意到我在重写 doPost() 方法以及显式调用超类构造函数时调用了 super.doPost(request, response);

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

当我注释掉时doPost() 语句中的 super.doPost(request, response); 运行得很好......

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

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

}

不用说,我需要重新阅读 super() 最佳实践:p

Bump...

I just had the same error. I noticed that I was invoking super.doPost(request, response); when overriding the doPost() method as well as explicitly invoking the superclass constructor

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

As soon as I commented out the super.doPost(request, response); from within doPost() statement it worked perfectly...

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

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

}

Needless to say, I need to re-read on super() best practices :p

没企图 2024-08-25 12:36:06

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

示例:

如果转发,

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

如果重定向,

    response.sendRedirect(roundTripURI);
    return;

You should add return statement while you are forwarding or redirecting the flow.

Example:

if forwardind,

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

if redirecting,

    response.sendRedirect(roundTripURI);
    return;
空城缀染半城烟沙 2024-08-25 12:36:06

这是因为您的 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块中

This is because your servlet is trying to access a request object which is no more exist..
A servlet's forward or include statement does not stop execution of method block. It continues to the end of method block or first return statement just like any other java method.

The best way to resolve this problem just set the page (where you suppose to forward the request) dynamically according your logic. That is:

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
}

and do the forward only once at last line...

you can also fix this problem using return statement after each forward() or put each forward() in if...else block

執念 2024-08-25 12:36:06

我删除了

        super.service(req, res);

然后它对我来说效果很好

I removed

        super.service(req, res);

Then it worked fine for me

淤浪 2024-08-25 12:36:06

在 returnforward 方法之后,您可以简单地执行以下操作:

return null;

它将打破当前范围。

After return forward method you can simply do this:

return null;

It will break the current scope.

み青杉依旧 2024-08-25 12:36:06

如果您在基于 Spring 的 Web 应用程序上看到此情况,请确保您的方法使用 @ResponseBody 进行注释,或者控制器使用 @RestController 而不是 @Controller 进行注释。如果方法返回 JSON,但尚未配置为将其作为响应,它也会抛出此异常,Spring 将转而查找 jsp 页面来渲染并抛出此异常。

If you see this on a Spring based web application, make sure you have your method annotated with @ResponseBody or the controller annotated with @RestController instead of @Controller. It will also throw this exception if a method returns JSON, but has not been configured to have that as the response, Spring will instead look for a jsp page to render and throw this exception.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文