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

Spring Boot移除Content-Length Header失败,求有效解决方案

问题

在Spring Boot 2.2.3 RELEASE版本应用中,未显式添加Content-Length请求头,但每个响应中自动包含该头部。现在需要为响应添加Transfer-Encoding头部,添加后通过Postman测试API时出现如下错误:

Error: Parse Error: Content-Length can't be present with Transfer-Encoding

该错误符合IETF HTTP 1.1 RFC7230文档规范。由于响应不需要Content-Length头部,我使用@WebFilter注解并设置@Order为Integer.MAX_VALUE(确保最后执行)编写了过滤器,代码如下:

@WebFilter(urlPatterns = "/*", asyncSupported = true)
@Order(Integer.MAX_VALUE)
public class ContentLengthHeaderFilter implements Filter {

    private static final Logger LOGGER = LoggerFactory.getLogger(ContentLengthHeaderFilter.class);

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        LOGGER.info("filter init called !!!");
        Filter.super.init(filterConfig);
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        LOGGER.info("doFilter called ...............@@@");
        chain.doFilter(request, new HttpServletResponseWrapper((HttpServletResponse) response) {

            @Override
            public void addHeader(String name, String value) {
                if (!HttpHeaders.CONTENT_LENGTH.equals(name)) {
                    LOGGER.info("adding header :" + name);
                    super.addHeader(name, value);
                }
            }

            @Override
            public void setHeader(String name, String value) {
                if (!HttpHeaders.CONTENT_LENGTH.equals(name)) {
                    LOGGER.info("setting header :" + name);
                    super.setHeader(name, value);
                }
            }
        });
    }

    @Override
    public void destroy() {
        LOGGER.info("filter destroy called !!!");
        Filter.super.destroy();
    }
}

日志显示除Content-Length外的其他头部已被正常添加:

13.10.2022 11:25:34.947+0530 INFO  [o.s.web.servlet.DispatcherServlet] [http-nio-8080-exec-1] Completed initialization in 8 ms
13.10.2022 11:25:34.959+0530 INFO  [a.b.c.d.ContentLengthHeaderFilter] [http-nio-8080-exec-1] doFilter called ...............@@@
13.10.2022 11:25:36.597+0530 INFO  [a.b.c.d.ContentLengthHeaderFilter] [http-nio-8080-exec-3] adding header :Location
13.10.2022 11:25:36.597+0530 INFO  [a.b.c.d.ContentLengthHeaderFilter] [http-nio-8080-exec-3] adding header :X-CustomHeader
13.10.2022 11:25:36.597+0530 INFO  [a.b.c.d.ContentLengthHeaderFilter] [http-nio-8080-exec-3] adding header :Transfer-Encoding

但API响应中仍存在Content-Length头部,导致上述错误。请问过滤器哪里出现问题?或者有其他移除该头部的方法吗?

解决方案

问题根源

你的过滤器只拦截了addHeader和setHeader方法,但Tomcat这类Servlet容器通常会通过setContentLength、setContentLengthLong这类专门的方法来设置Content-Length头部,这些方法没被你的包装类覆盖,所以容器依然会自动添加该头部。

修正后的过滤器代码

在HttpServletResponseWrapper中额外覆盖setContentLength和setContentLengthLong方法,直接忽略内容长度的设置:

@WebFilter(urlPatterns = "/*", asyncSupported = true)
@Order(Integer.MAX_VALUE)
public class ContentLengthHeaderFilter implements Filter {

    private static final Logger LOGGER = LoggerFactory.getLogger(ContentLengthHeaderFilter.class);

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        LOGGER.info("filter init called !!!");
        Filter.super.init(filterConfig);
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        LOGGER.info("doFilter called ...............@@@");
        chain.doFilter(request, new HttpServletResponseWrapper((HttpServletResponse) response) {

            @Override
            public void addHeader(String name, String value) {
                if (!HttpHeaders.CONTENT_LENGTH.equals(name)) {
                    LOGGER.info("adding header :" + name);
                    super.addHeader(name, value);
                }
            }

            @Override
            public void setHeader(String name, String value) {
                if (!HttpHeaders.CONTENT_LENGTH.equals(name)) {
                    LOGGER.info("setting header :" + name);
                    super.setHeader(name, value);
                }
            }

            @Override
            public void setContentLength(int len) {
                // 忽略Content-Length设置
                LOGGER.info("Ignoring setContentLength call");
            }

            @Override
            public void setContentLengthLong(long len) {
                // 忽略Content-Length设置
                LOGGER.info("Ignoring setContentLengthLong call");
            }
        });
    }

    @Override
    public void destroy() {
        LOGGER.info("filter destroy called !!!");
        Filter.super.destroy();
    }
}

其他可行方案

方案1:通过Spring Boot配置禁用自动Content-Length设置

在application.properties中添加以下配置:

server.tomcat.send-http2-alpn=false
server.tomcat.use-sendfile=false

该配置会让Tomcat不再自动计算并设置Content-Length,转而使用分块传输(对应Transfer-Encoding: chunked),无需编写额外代码。

方案2:使用ResponseBodyAdvice统一处理响应

实现ResponseBodyAdvice接口,在响应返回前主动移除Content-Length头部:

@ControllerAdvice
public class RemoveContentLengthAdvice implements ResponseBodyAdvice<Object> {

    @Override
    public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
        return true; // 对所有接口响应生效
    }

    @Override
    public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
        response.getHeaders().remove(HttpHeaders.CONTENT_LENGTH);
        return body;
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.16 15:57:16