RestTemplate位于:
org.springframework.web.client.RestTemplate
spring-web
他是Spring web模块提供的一个发送http请求的工具。在使用了Spring的应用中,使用这个工具是非常普遍的,使用的细节和特性是需要了解的。

一、设计思想

1、RestTempldate作为暴露给用户的使用类
2、RestTemplate继承抽象类org.springframework.http.client.support.InterceptingHttpAccessor
3、InterceptingHttpAccessor继承抽象类org.springframework.http.client.support.HttpAccessor
4、org.springframework.http.client.ClientHttpRequest接口是请求执行的入口,他是发送请求数据的工作者,实现类有多种,我们可以使用Apache的HttpClient、OkHttp3、Netty4都可,但这些都需要额外导包,默认情况下Spring使用的是java.net.HttpURLConnection。ClientHttpRequest接口中就一个方法:

public interface ClientHttpRequest extends HttpRequest, HttpOutputMessage {

	ClientHttpResponse execute() throws IOException;

}

5、ClientHttpRequest的产生是通过工厂来生产的
org.springframework.http.client.ClientHttpRequestFactory定义:

@FunctionalInterface
public interface ClientHttpRequestFactory {

	ClientHttpRequest createRequest(URI uri, HttpMethod httpMethod) throws IOException;

}

6、RestTemplate默认使用org.springframework.http.client.SimpleClientHttpRequestFactory作为生产ClientHttpRequest的工厂,它使用的java.net.HttpURLConnection来进行连接和发送数据。

二、使用经验

1、JDK <1.8 doesn't support getOutputStream with HTTP DELETE,也就是说如果JDK的版本低于1.8的话,那么Delete请求是不支持body体的。
2、对于默认HttpURLConnection有几个特点要注意:
a、HttpURLConnection对象不能直接构造,需要通过URL类中的openConnection()方法来获得
b、HttpURLConnection的connect()函数,实际上只是建立了一个与服务器的TCP连接,并没有实际发送HTTP请求。HTTP请求实际上直到我们获取服务器响应数据(如调用getInputStream()、getResponseCode()等方法)时才正式发送出去,所以配置信息都需要在connect()方法执行之前完成
c、HttpURLConnection是基于HTTP协议的,其底层通过socket通信实现。如果不设置超时(timeout),在网络异常的情况下,可能会导致程序僵死而不继续往下执行。请务必设置
d、HTTP正文的内容是通过OutputStream流写入的, 向流中写入的数据不会立即发送到网络,而是存在于内存缓冲区中,待流关闭时,根据写入的内容生成HTTP正文,调用getInputStream()方法时,返回一个输入流,用于从中读取服务器对于HTTP请求的返回信息。
e、HttpURLConnection.connect()不是必须的。当我们需要返回值时,比如我们使用HttpURLConnection.getInputStream()方法的时候它就会自动发送请求了,所以完全没有必要调用connect()方法了。
3、一般我们使用org.springframework.http.client.HttpComponentsClientHttpRequestFactory这个类来生产ClientHttpRequest,它使用的是apache的HttpClient库,功能齐全,没有古怪的使用规则。
4、在使用默认RestTemplate时,会将返回的Http状态码4系列,5系列时抛出异常,并且后续无法读取返回的body内容,最好的解决方案就是替换掉默认的SimpleClientHttpRequestFactory,使用HttpComponentsClientHttpRequestFactory:

restTemplate.setRequestFactory(new HttpComponentsClientHttpRequestFactory());