You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Servlet Filter中根据应用返回状态码添加自定义响应HTTP头

问题原因

当chain.doFilter(request, response)执行完成后,响应可能已经被提交(比如后端控制器已经输出响应内容并刷新了流),此时再调用setHeader修改响应头就不会生效——HTTP协议规定响应头必须在响应体之前发送,响应提交后无法再修改头信息。

解决方案

通过HttpServletResponseWrapper包装原始响应,提前捕获响应状态码,并确保在响应真正提交前设置自定义头。

1. 自定义响应包装类

这个类用于捕获并保存响应的状态码,同时委托所有操作给原始响应:

public class StatusCapturingResponseWrapper extends HttpServletResponseWrapper {
    private int statusCode = HttpServletResponse.SC_OK;

    public StatusCapturingResponseWrapper(HttpServletResponse response) {
        super(response);
    }

    @Override
    public void setStatus(int sc) {
        super.setStatus(sc);
        this.statusCode = sc;
    }

    @Override
    public void sendError(int sc) throws IOException {
        this.statusCode = sc;
        super.sendError(sc);
    }

    @Override
    public void sendError(int sc, String msg) throws IOException {
        this.statusCode = sc;
        super.sendError(sc, msg);
    }

    @Override
    public void setStatus(int sc, String sm) {
        super.setStatus(sc, sm);
        this.statusCode = sc;
    }

    public int getStatusCode() {
        return statusCode;
    }
}

2. 修改MDCFilter逻辑

使用包装类替代原始响应传递给过滤器链,在链执行完成后通过包装类获取状态码,再设置自定义头:

public class MDCFilter implements Filter {
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        String trackingId = UUID.randomUUID().toString();
        MDC.put("trackingId", trackingId);

        StatusCapturingResponseWrapper wrappedResponse = new StatusCapturingResponseWrapper((HttpServletResponse) response);

        try {
            chain.doFilter(request, wrappedResponse);
        } catch (Throwable throwable) {
            // 捕获异常时手动设置500状态码,确保头能被正确添加
            wrappedResponse.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
            // 若需要向上抛出异常,可取消下面注释
            // throw new ServletException(throwable);
        } finally {
            // 根据捕获到的状态码判断是否添加头
            if (wrappedResponse.getStatusCode() >= 300) {
                wrappedResponse.setHeader("x-tracking-id", trackingId);
            }
            MDC.remove("trackingId");
        }
    }
}

关键说明

  • 包装类会拦截所有修改状态码的操作,确保我们能获取到最终的响应状态。
  • 由于包装类的setHeader直接委托给原始响应,此时响应尚未提交(除非过滤器链中主动提交),所以头信息能被正常设置并发送给客户端。

内容的提问来源于stack exchange,提问作者mhrsalehi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.08 18:05:17