Java 响应提交后是否可以从 servlet 过滤器转发或重定向?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/3407000/
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
Is it possible to forward or redirect from a servlet filter after the response has been committed?
提问by
The logic is that the filter gets hit, the condition is not true, so it goes through the filter chain. After the response is committed, the filter gets hit, and the condition is now true (a request attribute was set). It goes in to execute the forward, but the page never forwards. I know this has something to do with the response being committed because I tested different logic where it forwards before it hits the chain for the first time, and it does forward successfully.
逻辑是过滤器被命中,条件不成立,所以它通过过滤器链。响应提交后,过滤器被命中,条件现在为真(设置了请求属性)。它进入执行转发,但页面从不转发。我知道这与提交的响应有关,因为我测试了它在第一次到达链之前转发的不同逻辑,并且它确实转发成功。
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest httpServletRequest = (HttpServletRequest)request;
if (some condition equals true) {
httpServletRequest.getRequestDispatcher("/home.jsp").forward(request, response);
return;
} else {
chain.doFilter(request, response);
}
}
Example from my deployment descriptor:
我的部署描述符中的示例:
<filter>
<filter-name>MyFilter</filter-name>
<filter-class>com.filters.MyFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>MyFilter</filter-name>
<url-pattern>*.jsp</url-pattern>
<dispatcher>REQUEST</dispatcher>
<dispatcher>FORWARD</dispatcher>
</filter-mapping>
采纳答案by Stephen C
The "committed" status of an HttpServletResponse
is really a way of saying whether the response headers have been written to the underlying socket. A "committed" response has had (at least) the first line written. Since the first line of the response contains the status code, it follows that you cannot change the status code of a committed response ... and that means it is too late to change the status to 3xx to do a redirect. Similarly, you cannot do a local forward because you've already started sending the response.
an 的“已提交”状态HttpServletResponse
实际上是一种说明响应头是否已写入底层套接字的方式。“提交”响应已经(至少)写了第一行。由于响应的第一行包含状态代码,因此您无法更改已提交响应的状态代码......这意味着将状态更改为 3xx 进行重定向为时已晚。同样,您不能进行本地转发,因为您已经开始发送响应。
回答by shams
You can achieve what you want by using a custom HttpServletResponse. You pass this wrapped HttpServletResponse down the filter chain. You can provide a local OutputStream that stores all the write requests, local variables to store the status code and headers. Once you are back in your filter you can then decide to perform the redirect or copy back the results from the local variables from the wrapper into the original ServletResponse (i.e. set the status code and header and copy the results from the local output stream into the servlet response's output stream).
您可以通过使用自定义HttpServletResponse来实现您想要的。您将这个包装好的 HttpServletResponse 向下传递到过滤器链。您可以提供一个存储所有写入请求的本地 OutputStream、存储状态代码和标头的本地变量。返回过滤器后,您可以决定执行重定向或将局部变量的结果从包装器复制回原始 ServletResponse(即设置状态代码和标头并将结果从本地输出流复制到servlet 响应的输出流)。
Edit:
编辑:
Refer to the Programming Customized Requests and Responsessection for a code example which uses a CharResponseWrapper
. The example uses a custom Writer, but it can be easily extended to an OutputStream. Based on how your Servlet is used, you need to override one or both of getWriter()
and getOutputStream()
to delay committing anything onto the original response. In addition, you will need to override isCommitted()
to return false
, so that the forward can be executed at any time down the filter chain. You will also need to override resetBuffer()
to initialize a new OutputStream
/Writer
to store the new content (including headers) after the redirect/forward.
参阅编程定制请求和响应对于其使用一个代码示例部分CharResponseWrapper
。该示例使用自定义 Writer,但它可以轻松扩展为 OutputStream。根据您的 Servlet 的使用方式,您需要覆盖其中一个或两个,getWriter()
并getOutputStream()
延迟将任何内容提交到原始响应上。此外,您需要覆盖isCommitted()
return false
,以便可以在过滤器链中随时执行转发。您还需要覆盖resetBuffer()
以初始化一个新的OutputStream
/Writer
以在重定向/转发后存储新内容(包括标头)。