繁体   English   中英

在过滤器中添加响应头?

[英]Adding header in response in filter?

我需要在每个响应中添加标题。 我打算在下面做

public class MyFilter extends OncePerRequestFilter {

    @Override
    protected void doFilterInternal(HttpServletRequest request,
                                    HttpServletResponse response, FilterChain filterChain)
            throws ServletException, IOException {

        filterChain.doFilter(request, response);
            response.addHeader("Access-Control-Allow-Origin", "*"); 
    }

}

我想在filterChain.doFilter(request, response)做,这样一旦控制器处理它,我只需在返回客户端之前添加标头。 这是正确的吗 ?

但是根据如何编写响应过滤器?

chain.doFilter返回之后,对响应执行任何操作都为时已晚。 此时,整个响应已经发送到客户端,您的代码无法访问它。

以上声明在我看来并不正确。 我不能在filterChain.doFilter(request, response)之后添加标头吗? 如果不是为什么?

我正在使用 spring mvc。

filterChain.doFilter之后,对响应执行任何操作都为时已晚。 此时,整个响应已经发送到客户端。

您需要将包装响应构建到您自己的类中,将这些包装器传递给doFilter方法并处理包装器中的任何处理。

已经有一个响应包装器:您可以扩展的HttpServletResponseWrapper 例如:

public class MyResponseRequestWrapper extends HttpServletResponseWrapper{
    public MyResponseRequestWrapper(HttpServletResponse response) {
        super(response);
    }
}

您的过滤器:

@Override
protected void doFilterInternal(HttpServletRequest request,
                                HttpServletResponse response, FilterChain filterChain)
        throws ServletException, IOException {

    HttpServletResponse myResponse = (HttpServletResponse) response;
    MyResponseRequestWrapper responseWrapper = new MyResponseRequestWrapper(myResponse);
    responseWrapper.addHeader("Access-Control-Allow-Origin", "*");
    filterChain.doFilter(request, myResponse);
}

我在我的 Spring 3.0.x 项目中使用它:

public class MyFilter extends OncePerRequestFilter {
    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException
    {
        response.addHeader("headerName", "headerValue");
        filterChain.doFilter(request, response);
    }
}

工作正常。

来自 Java EE 教程

修改响应的过滤器通常必须在响应返回给客户端之前捕获响应。 为此,您将一个替代流传递给生成响应的 servlet。 替代流可防止 servlet 在完成时关闭原始响应流,并允许过滤器修改 servlet 的响应。

为了将此替代流传递给 servlet,过滤器会创建一个响应包装器,该包装器覆盖 getWriter 或 getOutputStream 方法以返回此替代流。 包装器被传递给过滤器链的 doFilter 方法。 包装方法默认调用包装的请求或响应对象。 这种方法遵循设计模式中描述的著名的包装器或装饰器模式,

这有点晚了,但下面的内容可能会有所帮助所以如果您真的想将值附加到现有标头,或向现有标头添加新值,那么最好的方法是编写包装器并在包装器中设置值。

然后在过滤器中链接响应

HttpServletResponse response = (HttpServletResponse) servletResponse;
ByteArrayPrinter pw = new ByteArrayPrinter();

// Create a wrapper
HttpServletResponse wrappedResp = new HttpServletResponseWrapper(response) {

    @Override
    public void setContentType(final String type) {
        super.setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE);
    }

    @Override
    public PrintWriter getWriter() {
        return pw.getWriter();
    }

    // set the outputstream content type to JSON
    @Override
    public ServletOutputStream getOutputStream() throws IOException {
        ServletResponse response = this.getResponse();

        String ct = (response != null) ? response.getContentType() : null;
        if (ct != null && ct.contains(APPLICATION_XHTML)) {
            response.setContentType(ct + AppConstants.CONSTANT_COMMA + MediaType.APPLICATION_JSON_UTF8_VALUE);
        }
        return pw.getStream();
    }

};
chain.doFilter(httpRequest, wrappedResp);

这是 ByteArrayPrinter.java

public class ByteArrayPrinter {

    private ByteArrayOutputStream baos = new ByteArrayOutputStream();

    private PrintWriter pw = new PrintWriter(baos);

    private ServletOutputStream sos = new ByteArrayServletStream(baos);

    public PrintWriter getWriter() {
        return pw;
    }

    public ServletOutputStream getStream() {
        return sos;
    }

    byte[] toByteArray() {
        return baos.toByteArray();
    }
}

这是 ByteArrayServletOutputStream

public class ByteArrayServletStream extends ServletOutputStream {

    ByteArrayOutputStream baos;

    ByteArrayServletStream(ByteArrayOutputStream baos) {
        this.baos = baos;
    }

    @Override
    public void write(int param) throws IOException {
        baos.write(param);
    }

    @Override
    public boolean isReady() {
        // TODO Auto-generated method stub
        return false;
    }

    @Override
    public void setWriteListener(WriteListener listener) {
        // TODO Auto-generated method stub

    }

}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM