响应正在提交并且doFilter链被破坏

为了这是我需要发生的事情:

请求blah.com/test

  1. ServletFilter A – 创建配置文件,然后调用chain.doFilter
  2. ServletFilter B(由于url模式不匹配而被跳过)
  3. Servlet – 改变配置文件, repsonse.setStatusresponse.addHeader("Location", target)
  4. ServletFilter A – 应该根据配置文件创建一个cookie

实际发生了什么:

  1. ServletFilter A – 创建配置文件,然后调用chain.doFilter
  2. ServletFilter B(由于url模式不匹配而被跳过)
  3. Servlet – 改变配置文件, repsonse.setStatusresponse.addHeader("Location", target)
  4. 提交重定向,ServletFilter A不完成任务

我认为这可能与您可以在ServletFilter配置中设置的调度程序值有关。

有任何想法吗?

我认为响应在Step 4到达ServletFilter A时会被提交。 提交响应后,即将标头写入客户端,您无法执行需要添加标头的操作。 添加cookie等操作。

如果您希望在Step 4之前不提交响应,请尝试包装HttpServletResponse并返回缓冲数据的自定义输出流,直到它到达step 4 ,然后提交响应。

以下是示例代码:

 public class ResponseBufferFilter implements Filter { public void init(FilterConfig filterConfig) throws ServletException { } public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException, ServletException { HttpServletResponse httpResponse = (HttpServletResponse)response; BufferResponseWrapper wrapper = new BufferResponseWrapper(httpResponse); filterChain.doFilter(request, resposneWrapper); response.getOutputStream().write(wrapper .getWrapperBytes()); } public void destroy() { } private final class BufferResponseWrapper extends HttpServletResponseWrapper { MyServletOutputStream stream = new MyServletOutputStream(); public BufferResponseWrapper(HttpServletResponse httpServletResponse) { super(httpServletResponse); } public ServletOutputStream getOutputStream() throws IOException { return stream; } public PrintWriter getWriter() throws IOException { return new PrintWriter(stream); } public byte[] getWrapperBytes() { return stream.getBytes(); } } private final class MyServletOutputStream extends ServletOutputStream { private ByteArrayOutputStream out = new ByteArrayOutputStream(); public void write(int b) throws IOException { out.write(b); } public byte[] getBytes() { return out.toByteArray(); } } } 

它工作正常。 无论如何,重要的是要注意,如果缓冲的响应大小小于8KB,除非在调用getWrapperBytes()之前刷新响应,否则它将无法工作。

这是由于servlet-api内部实现。