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

使用Spring Boot RestTemplate时响应头Content-Type获取异常问题

解决RestTemplate获取Content-Type与工具不一致的问题

问题根源

  1. MediaType严格匹配导致误判:MediaType.equals()会严格匹配类型、子类型及参数(包括空格、大小写、参数顺序),比如服务器返回application/json; charset=utf-8,和MediaType.APPLICATION_JSON_UTF8(值为application/json;charset=UTF-8)会匹配失败。
  2. 请求Accept头差异:服务器可能根据请求的Accept头返回不同的Content-Type,RestTemplate默认的Accept头与Postman/curl不一致,导致返回的响应头不同。
  3. StringHttpMessageConverter的潜在影响:当用String.class接收响应时,部分版本的StringHttpMessageConverter可能会修改响应头的Content-Type(多数情况下不会,但需排查)。

解决方案

1. 优化Content-Type匹配逻辑

不要用equals做严格匹配,改用isCompatibleWith或直接检查类型子类型,忽略参数格式差异:

MediaType responseContentType = response.getHeaders().getContentType();
if (responseContentType != null && MediaType.APPLICATION_JSON.isCompatibleWith(responseContentType)) {
    // JSON响应逻辑
} else {
    // 其他类型响应逻辑
}

或者更直接的类型判断:

if (responseContentType != null 
        && "application".equals(responseContentType.getType()) 
        && "json".equals(responseContentType.getSubtype())) {
    // JSON响应逻辑
}

2. 统一请求头与工具一致

显式设置Accept头为*/*,和Postman/curl的默认行为对齐,确保服务器返回原始的Content-Type:

String url = "https://worldtimeapi.org/api/timezone/Europe/London";
HttpHeaders headers = new HttpHeaders();
headers.set("User-Agent", "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Safari/537.36");
// 显式设置Accept头,匹配工具默认行为
headers.set(HttpHeaders.ACCEPT, "*/*");
HttpEntity<String> entity = new HttpEntity<>(headers);
ResponseEntity<String> response = restTemplate.exchange(url, HttpMethod.GET, entity, String.class);

3. 禁用StringHttpMessageConverter的Content-Type修改(可选)

如果发现StringHttpMessageConverter影响了响应头,可以自定义转换器,禁止它修改Content-Type:

RestTemplate restTemplate = new RestTemplate();
for (HttpMessageConverter<?> converter : restTemplate.getMessageConverters()) {
    if (converter instanceof StringHttpMessageConverter) {
        StringHttpMessageConverter stringConverter = (StringHttpMessageConverter) converter;
        stringConverter.setWriteAcceptCharset(false);
        break;
    }
}

4. 直接获取原始响应头(极端情况)

如果上述方法都无效,可以直接获取原始的响应头字符串,避免MediaType解析的差异:

List<String> contentTypeHeaders = response.getHeaders().get(HttpHeaders.CONTENT_TYPE);
if (contentTypeHeaders != null && !contentTypeHeaders.isEmpty()) {
    String contentType = contentTypeHeaders.get(0);
    if (contentType.startsWith("application/json")) {
        // JSON响应逻辑
    }
}

适配动态URL的注意事项

  • 所有配置都应全局应用到RestTemplate实例,确保所有动态请求都使用相同的规则。
  • 避免针对单个URL做特殊处理,保持逻辑通用性,适应响应体和Content-Type的动态变化。
  • 可以添加日志记录响应的原始Content-Type,方便排查后续的差异问题:
List<String> rawContentType = response.getHeaders().get(HttpHeaders.CONTENT_TYPE);
log.info("Raw Content-Type from {}: {}", url, rawContentType);

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.13 17:22:42