Spring解析Content-Type报InvalidMediaTypeException解决方法咨询
使用Spring调用REST API时,接口返回的响应头携带字段:Content-Type: multipart/mixed; boundary==_123456789。Spring解析该Content-Type时,判定boundary令牌中存在非法的'='字符,直接抛出InvalidMediaTypeException异常,导致无法正常解析响应结果。
Spring没有提供直接禁用该MediaType校验规则的配置入口,该校验逻辑严格遵循HTTP/MIME协议规范,问题本质是接口返回的Content-Type格式不符合标准:按照RFC 2045定义,MIME参数格式为参数名=参数值,上述响应头中boundary参数多拼接了一个等号,属于服务端输出错误。
org.springframework.http.InvalidMediaTypeException: Invalid mime type "multipart/mixed; boundary==_11204303fda4403b6a72d61500081354": Invalid token character '=' in token "=_11204303fda4403b6a72d61500081354" at org.springframework.http.MediaType.parseMediaType(MediaType.java:620) at org.springframework.http.HttpHeaders.getContentType(HttpHeaders.java:992) at org.springframework.web.client.HttpMessageConverterExtractor.getContentType(HttpMessageConverterExtractor.java:136) at org.springframework.web.client.HttpMessageConverterExtractor.extractData(HttpMessageConverterExtractor.java:93) at org.springframework.web.client.RestTemplate$ResponseEntityResponseExtractor.extractData(RestTemplate.java:1037) at org.springframework.web.client.RestTemplate$ResponseEntityResponseExtractor.extractData(RestTemplate.java:1020) at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:778) at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:711) at org.springframework.web.client.RestTemplate.postForEntity(RestTemplate.java:468)
方案1(优先推荐,无侵入兼容):通过客户端拦截器修正非法响应头
在RestTemplate的请求拦截器中,提前拿到原始响应,把Content-Type里多余的boundary==替换为标准的boundary=,修正后再交给Spring的解析逻辑处理,不需要修改Spring内部逻辑,也不需要服务端配合。
实现代码如下:import org.springframework.http.HttpHeaders; import org.springframework.http.HttpRequest; import org.springframework.http.client.ClientHttpRequestExecution; import org.springframework.http.client.ClientHttpRequestInterceptor; import org.springframework.http.client.ClientHttpResponse; import java.io.IOException; import java.util.Collections; public class MalformedContentTypeFixInterceptor implements ClientHttpRequestInterceptor { @Override public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException { ClientHttpResponse response = execution.execute(request, body); HttpHeaders headers = response.getHeaders(); String rawContentType = headers.getFirst(HttpHeaders.CONTENT_TYPE); // 匹配非法的双等号格式并替换 if (rawContentType != null && rawContentType.contains("boundary==")) { String fixedContentType = rawContentType.replace("boundary==", "boundary="); headers.set(HttpHeaders.CONTENT_TYPE, fixedContentType); } return response; } } // 初始化RestTemplate时注册拦截器即可 RestTemplate restTemplate = new RestTemplate(); restTemplate.setInterceptors(Collections.singletonList(new MalformedContentTypeFixInterceptor())); // 后续正常使用restTemplate调用接口即可方案2(根源解决):协调接口提供方修复响应头格式
该问题的本质是服务端输出Content-Type时拼接错误,多写了一个等号。如果可以协调接口方修改,直接把响应头调整为标准格式Content-Type: multipart/mixed; boundary=_123456789,所有客户端都不需要做额外兼容,是最规范的解决方式。方案3(备选):自定义响应转换器修正Content-Type
如果项目中有自定义HttpMessageConverter的需求,可以重写转换器中读取Content-Type的逻辑,在调用MediaType.parseMediaType前先对字符串做替换修正,该方案侵入性高于拦截器方案,仅适合已有自定义转换器逻辑的场景使用。
注意:不建议通过反射修改Spring内部MediaType的解析逻辑、或者替换内置的解析类,这类方式会破坏Spring的标准校验流程,后续版本升级容易出现兼容性问题,维护成本极高。
内容的提问来源于stack exchange,提问作者Magnarox06

