【问题标题】:Java Servlet Filter - Modify response headers based on statusJava Servlet 过滤器 - 根据状态修改响应标头
【发布时间】:2017-06-25 07:30:51
【问题描述】:

我正在尝试编写一个 servlet 过滤器,该过滤器将根据请求的状态将标头添加到响应中。我知道我必须在传递给chain.doFilter 之前用 HttpServletResponseWrapper 包装响应,但标头永远不会被发送,所以我显然遗漏了一些非常明显的东西。

代码看起来像:

@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException
{
   HttpServletResponse httpServletResponse = (HttpServletResponse) response;
   HttpServletResponseWrapper responseWrapper = new HttpServletResponseWrapper(httpServletResponse);

   chain.doFilter(request, responseWrapper);

   if(responseWrapper.getStatus() < 400)
   {
      responseWrapper.addHeader("X-Custom-Foobar", "abc");
   }
}

在检查完成之前,我必须在包装器中捕获一些内容以防止响应发送到客户端吗?

【问题讨论】:

    标签: java servlet-filters


    【解决方案1】:

    所以这个规范令人沮丧的部分是你必须完全拦截ServletOutputStream 并缓冲它。我最终在这里遵循了这个例子 :: https://stackoverflow.com/a/11027170/76343

    基类HttpServletResponseWrapper 是一个完整的传递,一旦输出流关闭,对响应的所有进一步修改都将被静音。

    不幸的是,似乎没有更优雅的方式来实现这一点。

    【讨论】:

      【解决方案2】:

      您需要扩展 HttpResponseWrapper() 并覆盖适当的方法。仅仅使用香草HttpResponseWrapper 本身并没有任何作用。

      【讨论】:

      • @downvoter 它完成了什么?比如什么?如何?即使它是一个完整的传递,正如其他答案所指出的那样?公众有知情权。
      【解决方案3】:

      这段代码的顺序颠倒了:

         chain.doFilter(request, responseWrapper);
      
         if(responseWrapper.getStatus() < 400)
         {
            responseWrapper.addHeader("X-Custom-Foobar", "abc");
         }
      

      试试这个:

         if(responseWrapper.getStatus() < 400)
         {
            responseWrapper.addHeader("X-Custom-Foobar", "abc");
         }
      
         chain.doFilter(request, responseWrapper);
      

      doFilter 方法直到在线发送响应后才会返回到您的方法。

      【讨论】:

        【解决方案4】:

        这实际上是可能的。但是因为在调用chain.doFilter(request, response)之后响应已经提交了,所以我们必须在收到状态码之后,但是在响应提交之前设置headers。这是一个例子:

        public class HeadersFilter implements Filter {
        
            @Override
            public void init(FilterConfig filterConfig) {
            }
        
            @Override
            public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException,
                                                                                                     ServletException {
        
                HttpServletRequest request = (HttpServletRequest) req;
                HttpServletResponse response = (HttpServletResponse) resp;
        
                chain.doFilter(request, new ResponseWrapper(response));
            }
        
            public static class ResponseWrapper extends HttpServletResponseWrapper {
                public ResponseWrapper(HttpServletResponse response) {
                    super(response);
                }
        
                @Override
                public void setStatus(int sc) {
                    super.setStatus(sc);
        
                    // SET YOUR HEADERS HERE
                    // setHeader("Cache-Control", "no-cache, no-store, must-revalidate");
                }
            }
        
            @Override
            public void destroy() {
            }
        }
        

        【讨论】:

        • 你真的运行过这个吗? setStatus(int sc) 从未被调用过。所以不能设置标题。
        • @PaulUszak 我不仅运行了这个,而且我的生产中的代码与这个非常相似。如果没有为您调用setStatus(int sc),您如何假设响应返回没有任何状态?
        • 对不起伙计,我在super.setStatus(sc);下面放了一个打印语句,我的机器上没有调用它。包装器已创建,但未调用该方法。如果您随后添加古怪的自定义标头,则不会添加它们。我正在运行 Tomcat 9。没关系,因为我已经用另一种方式解决了:-)
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2016-11-19
        • 2017-01-02
        • 2012-11-07
        • 1970-01-01
        • 2019-04-29
        • 2023-03-30
        • 2021-12-27
        相关资源
        最近更新 更多