在 Java 社區中,HTTP Client 主要有 JDK 的 HttpURLConnection、Apache的Http Client、Square 公司開源的 OkHttp。
1.RestTemplate簡介和使用
除了這幾個純粹的 HTTP Client 類庫以外, Spring 的 RestTemplate針對 Web Service 場景,尤其是 RESTful Web Service。它基於前面提到的 HTTP Client ,並在其基礎上提供了消息轉換、參數映射等對於 Web Service 來說十分必要的功能。
詳細查看 RestTemplate API。
2.RestTemplate中http報文轉換處理
2.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。
2.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請求頭中。
2.3 一個陷阱
StringHttpMessageConverter默認使用ISO-8859-1編碼,中文會出現亂碼,可以統一改爲utf-8。修改的方法網上一堆,這裏就不寫了。當然你也可以選擇不使用String