Java Servlet:提交响应后无法转发

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/18211497/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 23:21:13  来源:igfitidea点击:

Servlet: Cannot forward after response has been committed

javaservletsgeolocationresponse.redirectforward

提问by tokhi

I'm working on servlet page that renders content based on geo-location, and I want to use both sendRedirectand forwardtogether; e.g; you browse example.com/aPage.jspfrom France; first I want the servlet to redirect you to example.com/fr/aPage.jspand then forward you to the resourcespage.

我工作的基础上呈现的内容servlet页面上geo-location,我想同时使用sendRedirectforward在一起; 例如; 您浏览example.com/aPage.jspFrance; 首先,我希望 servlet 将您重定向example.com/fr/aPage.jsp到该resources页面,然后将您转发到该页面。

This is what I have in my servlet:

这是我的 servlet 中的内容:

public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
  ....
  response.sendRedirect(REDIRECT_URL_BASED_ON_GEO);
  // after redirect forward the resources page
  RequestDispatcher view = request.getRequestDispatcher(RESOURCES_PAGE);
  view.forward(request, response);
  ...
}

But I get:

但我得到:

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

I know the error appears becauseI can't use both sendRedirectand forwardone after another, but I don't know how to achieve what I want (as described above) without this.

我知道,因为出现错误,我不能同时使用sendRedirectforward一个又一个,但我不知道该如何实现我想要的东西没有这个(如上所述)。

any help?

有什么帮助吗?

回答by nanofarad

Once you redirect, the servlet you're working on is no longer in control. You need to get the servlet that is the targetof the redirect to recognize the correct condition to forward and then call forward there, with similar code:

重定向后,您正在处理的 servlet 不再受控制。您需要获取作为重定向目标的 servlet以识别要转发的正确条件,然后在那里调用转发,使用类似的代码:

RequestDispatcher view = request.getRequestDispatcher(RESOURCES_PAGE);
view.forward(request, response);

Even if it's the same servlet, it's a new invocation of the servlet's doGet(or other similar method.

即使它是同一个 servlet,它也是对 servletdoGet(或其他类似方法的新调用。

回答by Sotirios Delimanolis

When you call

你打电话时

response.sendRedirect(REDIRECT_URL_BASED_ON_GEO);

you are sending your client a 302 HTTP status code with the location to redirect to. Your client then needs to make a new HTTP request to that location. Whichever Servlet is supposed to handle the path REDIRECT_URL_BASED_ON_GEOshould then use the RequestDispatcherto forward to the resource described by RESOURCES_PAGE.

您正在向您的客户端发送 302 HTTP 状态代码以及要重定向到的位置。然后,您的客户端需要向该位置发出新的 HTTP 请求。无论哪个 Servlet 应该处理路径,REDIRECT_URL_BASED_ON_GEO都应该使用RequestDispatcher转发到由 描述的资源RESOURCES_PAGE

To better explain your exception

为了更好地解释您的异常

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

a committed response is a response where HTTP headers are already sent. If we look at your code

已提交的响应是已发送 HTTP 标头的响应。如果我们查看您的代码

response.sendRedirect(REDIRECT_URL_BASED_ON_GEO);

After this line, you've already sent the response along with the headers (302).

在此行之后,您已经将响应与标头 (302) 一起发送。

RequestDispatcher view = request.getRequestDispatcher(RESOURCES_PAGE);
view.forward(request, response);

After these lines, you're asking the resource RESOURCES_PAGEto finish processing the request. That includes writing HTTP headers and body. But the request has already been processed and a response has already been sent, so it will fail, throwing the exception.

在这些行之后,您要求资源RESOURCES_PAGE完成对请求的处理。这包括编写 HTTP 标头和正文。但是请求已经被处理并且已经发送了响应,所以它会失败,抛出异常。

回答by Suresh Atta

 response.sendRedirect(REDIRECT_URL_BASED_ON_GEO);
  // after redirect forward the resources page

After that line , Your response start writing to clinet.

在该行之后,您的回复开始写入 clinet。

And you are trying to add additional data to it.

您正在尝试向其中添加其他数据。

The server has already finishedwriting the response header and is writing the body of the content, and which point you are trying to write more to the header - of course it cant rewind.

服务器已经完成了响应标头的写入并正在写入内容的主体,并且您正在尝试向标头写入更多内容 - 当然它不能倒带。

So,Thumb rule while dealing with servlet is

所以,处理 servlet 时的拇指规则是

Finish your logic before redirector forwardadd return statement.So execution ends there .

在之前完成您的逻辑 redirectforward添加 return 语句。因此执行到此结束。

回答by Sir RotN

You have to be aware that a redirect is a complete response to the browser and the browser will in turn issue a new request to the url you redirected to. Even though you can't really sse it when dealing with the browser you always have to be aware that this is what happens.

您必须注意重定向是对浏览器的完整响应,浏览器将依次向您重定向到的 url 发出新请求。即使在与浏览器打交道时您无法真正理解它,您也必须始终意识到这就是发生的事情。

Now, if you use the same controller for the second request you have to check wether a redirect is necessary or you can now do the forward instead.

现在,如果您对第二个请求使用相同的控制器,您必须检查是否需要重定向,或者您现在可以改为执行转发。

if (!path.startsWith(locationPrefix)) {
  response.sendRedirect(locationPrefix + path);
  return;
} else {
  RequestDispatcher view = request.getRequestDispatcher(RESOURCES_PAGE);
  view.forward(request, response);
  return;
}

Of course it would be nicer to have a distinct controller per request, but depending of url structure and framework this is not always possible.

当然,每个请求有一个不同的控制器会更好,但取决于 url 结构和框架,这并不总是可行的。