使用RestTemplate请求某第三方API时,当未添加 系统中的convert时会出现406错误,添加了convert后,会出现中文乱码。
调查结果:
- 406是因为 该第三方API需要Accept为"text/plain"或*/*或其他的(我不知道他具体要什么),
- 请求头中的中文乱码是当Accept为"text/plain"时响应即为中文乱码。
源码跟踪:
org.springframework.web.client.RestTemplate.AcceptHeaderRequestCallback#doWithRequest
技术点:
RestTemplate会把它的MessageConverters支持的媒体类型(即可解析的媒体类型)放到Accept中发送该请求。
业务问题:
因为第三方API的设定http请求中的Accept中不包含*/*或"text/plain"时会响应406。
技术问题:
没有MessageConverter可支持*/*或"text/plain"。
解决方案:
添加MessageConverter可支持*/*
@Override
public void doWithRequest(ClientHttpRequest request) throws IOException {
if (this.responseType != null) {
Class<?> responseClass = null;
if (this.responseType instanceof Class) {
responseClass = (Class<?>) this.responseType;
}
List<MediaType> allSupportedMediaTypes = new ArrayList<>();
for (HttpMessageConverter<?> converter : getMessageConverters()) {
if (responseClass != null) {
if (converter.canRead(responseClass, null)) {
allSupportedMediaTypes.addAll(getSupportedMediaTypes(converter));
}
}
else if (converter instanceof GenericHttpMessageConverter) {
GenericHttpMessageConverter<?> genericConverter = (GenericHttpMessageConverter<?>) converter;
if (genericConverter.canRead(this.responseType, null, null)) {
// 请求发出之前,根据RestTemplate的Converts能转换哪些,放到Accept中发送该请求。
allSupportedMediaTypes.addAll(getSupportedMediaTypes(converter));
}
}
}
if (!allSupportedMediaTypes.isEmpty()) {
MediaType.sortBySpecificity(allSupportedMediaTypes);
if (logger.isDebugEnabled()) {
logger.debug("Setting request Accept header to " + allSupportedMediaTypes);
}
request.getHeaders().setAccept(allSupportedMediaTypes);
}
}
Accpet和ContentType:
1.Accept属于请求头, Content-Type属于实体头。
Http报头分为通用报头,请求报头,响应报头和实体报头。
请求方的http报头结构:通用报头|请求报头|实体报头
响应方的http报头结构:通用报头|响应报头|实体报头
2.Accept代表发送端(客户端)希望接受的数据类型。
比如:Accept:text/xml(application/json);
代表客户端希望接受的数据类型是xml(json )类型
Content-Type代表发送端(客户端|服务器)发送的实体数据的数据类型。
比如:Content-Type:text/html(application/json) ;
代表发送端发送的数据格式是html(json)。
二者合起来,
Accept:text/xml;
Content-Type:text/html
即代表希望接受的数据类型是xml格式,本次请求发送的数据的数据格式是html。