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

Spring Boot升级到3.2.5后RestTemplate空请求丢失Content-Length致411错误

问题描述

将Spring Boot从3.1.x升级到3.2.5后,RestTemplate发送空请求体的POST请求时出现以下异常行为:

  • 不再自动添加Content-Length: 0请求头
  • 手动显式添加该请求头也会被RestTemplate丢弃
    最终导致目标服务器返回HTTP 411 Length Required错误。

升级前后请求日志对比(日志来自DEBUG级别的o.a.h.c.h.i.Wire.wire(92) - http-outgoing-0):

Spring Boot 3.1.10 请求日志

---- >> "POST /oauth2/token HTTP/1.1[\r][\n]"
---- >> "Accept: text/plain, application/json, application/*+json, */*[\r][\n]"
---- >> "Authorization: Basic ******=[\r][\n]"
---- >> "grant_type: client_credentials[\r][\n]"
---- >> "scope: you don't need this[\r][\n]"
---- >> "Content-Type: application/x-www-form-urlencoded[\r][\n]"
---- >> "Accept-Encoding: gzip, x-gzip, deflate[\r][\n]"
---- >> "Content-Length: 0[\r][\n]"
---- >> "Host: this one too[\r][\n]"
---- >> "Connection: keep-alive[\r][\n]"
---- >> "User-Agent: Apache-HttpClient/5.2.1 (Java/17.0.10)[\r][\n]"
---- >> "[\r][\n]"

Spring Boot 3.2.5 请求日志

---- >> "POST /oauth2/token HTTP/1.1[\r][\n]"
---- >> "Accept: text/plain, application/json, application/*+json, */*[\r][\n]"
---- >> "Authorization: Basic ****=[\r][\n]"
---- >> "grant_type: client_credentials[\r][\n]"
---- >> "scope: you don't need this[\r][\n]"
---- >> "Content-Type: application/x-www-form-urlencoded[\r][\n]"
---- >> "Accept-Encoding: gzip, x-gzip, deflate[\r][\n]"
---- >> "Host: this one too[\r][\n]"
---- >> "Connection: keep-alive[\r][\n]"
---- >> "User-Agent: Apache-HttpClient/5.2.1 (Java/17.0.10)[\r][\n]"
解决方案

1. 临时快速修复:使用空字符串作为请求体

将原本的空请求体替换为空字符串"",RestTemplate会自动为其添加Content-Length: 0头,简单直接:

restTemplate.postForObject(url, "", YourResponse.class);

2. 自定义拦截器强制添加Content-Length头

实现ClientHttpRequestInterceptor,在请求发送前检查空体并手动添加头:

public class EmptyBodyContentLengthInterceptor implements ClientHttpRequestInterceptor {
    @Override
    public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException {
        if (body.length == 0 && !request.getHeaders().containsKey(HttpHeaders.CONTENT_LENGTH)) {
            request.getHeaders().setContentLength(0);
        }
        return execution.execute(request, body);
    }
}

注册到RestTemplate:

restTemplate.getInterceptors().add(new EmptyBodyContentLengthInterceptor());

3. 调整FormHttpMessageConverter的空体处理

针对application/x-www-form-urlencoded类型的请求,修改转换器配置确保空表单生成Content-Length: 0:

restTemplate.getMessageConverters().stream()
    .filter(c -> c instanceof FormHttpMessageConverter)
    .findFirst()
    .ifPresent(c -> ((FormHttpMessageConverter) c).setWriteEmptyForm(true));

4. 配置底层Apache HttpClient行为

如果RestTemplate使用Apache HttpClient作为请求工厂,通过拦截器强制为空体请求添加头:

CloseableHttpClient httpClient = HttpClientBuilder.create()
    .addInterceptorFirst((HttpRequestInterceptor) (request, context) -> {
        if (request instanceof HttpEntityEnclosingRequest entityRequest) {
            if (entityRequest.getEntity() == null || entityRequest.getEntity().getContentLength() == -1) {
                entityRequest.setHeader(HttpHeaders.CONTENT_LENGTH, "0");
            }
        }
    })
    .build();

restTemplate.setRequestFactory(new HttpComponentsClientHttpRequestFactory(httpClient));
原因说明

该行为变化源于Spring Boot 3.2对应的Spring Framework 6.1版本中,RestTemplate底层请求处理逻辑的调整,尤其是针对空请求体的Content-Length头生成规则。Apache HttpClient 5.x的相关行为变更也可能影响了最终结果,该调整未在Spring Boot 3.2的发布说明中单独列出。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 11:25:01