前言
在阅读本篇之前,建议先阅读开山篇效果更佳。RestTemplate是Spring提供的用于访问Rest服务的客户端工具,它提供了多种便捷访问远程Http服务的方法,能够大大提高客户端的编写效率。
弱弱呼吁一句:对于那些在Spring环境下还在使用HttpClient(或其它Client)的同学,今儿看完本文后,建议切换到RestTemplate (有特殊需求的当然除外喽~)。
RestTemplate简化了与http服务的通信,程序代码可以给它提供URL,并提取结果。它默认使用的JDK 的HttpURLConnection进行通信,然而我们是可以通过RestTemplate.setRequestFactory切换到不同的HTTP源:如Apache HttpComponents、Netty、OkHttp等等。
RestOperations
指定一组基本restful操作的接口,定义了基本的Rest操作集合,它的唯一实现是RestTemplate;不直接使用,但这是增强可测试性的一个有用选项,因为它很容易被模拟或存根(后面这句话请好好理解)。
可以对比参照RedisOperations,它的实现类也只有RedisTemplate一个。他俩都采用了设计模式中的模板模式
方法们:
由于此接口里的方法实在太多了(40+个),因此我按照Http标准进行分类如下表格:
// @since 3.0 public enum HttpMethod { GET, HEAD, POST, PUT, PATCH, DELETE, OPTIONS, TRACE; ... }
观察发现,虽然方法众多但有很强的规律可循。每个方法都有三种重载实现:2种的url参数为字符串,一种URI参数,所以掌握规律后再使用,就不用害怕它的多而不知咋使用了。
xxxForObject:返回响应体(也就直接是body体力的内容) (T)
xxxForEntity:返回的相应行、响应头、响应码、响应体等等 (ResponseEntity)
xxxForLocation:提交成功之后,返回新资源的URI。这个只需要服务提供者返回一个 URI 即可,该 URI 表示新资源的位置,可谓非常轻量。 (URI)
注意:使用字符串类型的url默认会对url进行转义,如http://example.com/hotel list在执行时会转义为http://example.com/hotel%20list,隐式的转义这样是没有问题的。但如果你自己已经转义过了,那就不ok了。
若不想要这种隐式的转义,建议使用URI(URI uri = uriComponents.toUri())来构造。
RestTemplate中POST请求的三种方式
post请求代表新建/创建一个资源,所以它是有返回值的。因为它的使用最为复杂,因此本文以它为例进行讲解。
你如果熟练使用过浏览器的开发者工具调试过,你肯定知道POST请求它传参是有两种方式的:
- Form Data方式:我们用from表单提交的方式就是它;使用ajax(注意:这里指的是jQuery的ajax,而不是源生js的)默认的提交方式也是它~
2.request payload方式:多部分方式/json方式
这两种方式是通过Content-Type来区别的:若是application/x-www-form-urlencoded那就是formdata方式;若是application/json或者multipart/form-data等方式那就是request payload方式
jQuery在执行post请求时,默认会给你设置Content-Type为application/x-www-form-urlencoded,所以服务器能够正确解析。
若使用js原生的ajax,如果不显示的设置Content-Type,那么默认是text/plain,这时服务器就不知道怎么解析数据了,所以才只能通过获取原始数据流的方式来进行解析请求数据。(相信没人这么干吧~)
exchange和execute方法:
exchange方法:更通用的请求方法。它入参必须接受一个RequestEntity,从而可以设置请求的路径、头等等信息,最终全都是返回一个ResponseEntity(可以发送Get、Post、Put等所有请求)。
execute方法:最最最底层、通用的请求方法。
RequestCallback:用于操作请求头和body,在请求发出前执行;ResponseExtractor:解析/提取HTTP响应的数据,而且不需要担心异常和资源的关闭
RequestCallback.doWithRequest(ClientHttpRequest)说白了就是拿到ClientHttpRequest后对他进行继续处理~
RestTemplate的acceptHeaderRequestCallback、httpEntityCallback这些方法可以设置它~
HttpAccessor、InterceptingHttpAccessor
这两个抽象类不容忽视,HystrixCommand和Ribbon的逻辑都和它有关系(拦截器)。
HttpAccessor是个抽象基类,它定义要操作ClientHttpRequestFactory的公共属性,它一般不直接使用。
// @since 3.0 public abstract class HttpAccessor { // RestTemplate默认使用的客户端工厂:基于源生JDK private ClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory(); // 若要切换成三方库的底层组件,设置此方法便可 public void setRequestFactory(ClientHttpRequestFactory requestFactory) { this.requestFactory = requestFactory; } ... // get方法 // 供给子类非常方便的拿到一个ClientHttpRequest protected ClientHttpRequest createRequest(URI url, HttpMethod method) throws IOException { ClientHttpRequest request = getRequestFactory().createRequest(url, method); return request; } }
它的子类是:InterceptingHttpAccessor,也还是个抽象实现,主要是管理起了请求的拦截器们:ClientHttpRequestInterceptor。