在 Java 社区中,HTTP Client 主要有 JDK 的 HttpURLConnection、Apache Commons HttpClient(Apache HttpClient 3.x)、Apache HttpComponents Client(Apache HttpClient 4.x)、Square 公司开源的 OkHttp。
1.RestTemplate简介
除了这几个纯粹的 HTTP Client 类库以外, Spring框架提供的RestTemplate类可用于在应用中调用rest服务,它简化了与http服务的通信方式,统一了RESTful的标准,封装了http链接, 我们只需要传入url及返回值类型即可。
RestTemplate默认依赖JDK提供http连接的能力(HttpURLConnection),如果有需要的话也可以通过setRequestFactory方法替换为例如Apache HttpComponents、或OkHttp等其它HTTP library。并在其基础上提供了消息转换、参数映射等对于 Web Service 来说十分必要的功能。
RestTemplate包含以下几个部分:
- HttpMessageConverter 对象转换器
- ClientHttpRequestFactory 默认是JDK的HttpURLConnection
- ResponseErrorHandler 异常处理
- ClientHttpRequestInterceptor 请求拦截器
用一张图可以很直观的理解:
restemplate.png
2.RestTemplate用法
restem.png详细查看
RestTemplate API
SpringBoot系列 - 使用RestTemplate
3.RestTemplate中http报文转换处理
3.1 HttpMessageConverter
默认情况下RestTemplate自动帮我们注册了一组HttpMessageConverter用来处理一些不同的contentType的请求。
public RestTemplate() {
this.messageConverters = new ArrayList();
this.errorHandler = new DefaultResponseErrorHandler();
this.uriTemplateHandler = new DefaultUriBuilderFactory();
this.headersExtractor = new RestTemplate.HeadersExtractor();
this.messageConverters.add(new ByteArrayHttpMessageConverter());
this.messageConverters.add(new StringHttpMessageConverter());
this.messageConverters.add(new ResourceHttpMessageConverter(false));
this.messageConverters.add(new SourceHttpMessageConverter());
this.messageConverters.add(new AllEncompassingFormHttpMessageConverter());
if (romePresent) {
this.messageConverters.add(new AtomFeedHttpMessageConverter());
this.messageConverters.add(new RssChannelHttpMessageConverter());
}
if (jackson2XmlPresent) {
this.messageConverters.add(new MappingJackson2XmlHttpMessageConverter());
} else if (jaxb2Present) {
this.messageConverters.add(new Jaxb2RootElementHttpMessageConverter());
}
if (jackson2Present) {
this.messageConverters.add(new MappingJackson2HttpMessageConverter());
} else if (gsonPresent) {
this.messageConverters.add(new GsonHttpMessageConverter());
} else if (jsonbPresent) {
this.messageConverters.add(new JsonbHttpMessageConverter());
}
if (jackson2SmilePresent) {
this.messageConverters.add(new MappingJackson2SmileHttpMessageConverter());
}
if (jackson2CborPresent) {
this.messageConverters.add(new MappingJackson2CborHttpMessageConverter());
}
}
其中常用的Converter:
StringHttpMessageConverter处理text/plain;
AllEncompassingFormHttpMessageConverter处理application/x-www-form-urlencoded, multipart/form-data
MappingJackson2HttpMessageConverter处理application/json;
MappingJackson2XmlHttpMessageConverter处理application/xml。
3.2 RestTemplate请求中的报文转换
当我们发送请求时,RestTemplate 从这组HttpMessageConverter中循环取出HttpMessageConverter,并通过canWrite((Type)requestBodyType, requestBodyClass, requestContentType)
方法判断当前的HttpMessageConverter是否合适。
requestBodyType和requestBodyClass是body数据类型。
requestContentType是我们设置的contentType。
public boolean canWrite(Class<?> clazz, @Nullable MediaType mediaType) {
//当前的HttpMessageConverter是否支持转换body数据类型
//&设置的contentType是否支持转换(这里其实只是检验contentType是否在RestTemplate支持的MediaType中)
return this.supports(clazz) && this.canWrite(mediaType);
}
protected boolean canWrite(@Nullable MediaType mediaType) {
if (mediaType != null && !MediaType.ALL.equals(mediaType)) {
Iterator var2 = this.getSupportedMediaTypes().iterator();
MediaType supportedMediaType;
do {
if (!var2.hasNext()) {
return false;
}
supportedMediaType = (MediaType)var2.next();
} while(!supportedMediaType.isCompatibleWith(mediaType));
return true;
} else {
return true;
}
}
通过上面的代码和里面的增加的注释,我们可以确定RestTemplate是根据我们传入body的类型来选择HttpMessageConverter,设置的contentType只要RestTemplate支持即可,并不会左右HttpMessageConverter的选择。但是contentType会被加到http请求头中。
3.3 一个陷阱
StringHttpMessageConverter默认使用ISO-8859-1编码,中文会出现乱码,可以统一改为utf-8。修改的方法网上一堆,这里就不写了。当然你也可以选择不使用String
网友评论