10.HttpClient、RestTemplate、OkHttp特点? RestTemplate请求模板详细使用

目录


Spring MVC专栏目录(点击进入…)



HttpClient、RestTemplate、OkHttp特点

远程调用方式描述
HttpClient代码复杂,还得操心资源回收等。代码很复杂,冗余代码多,不建议直接使用
RestTemplateSpring提供的用于访问Rest服务的客户端,RestTemplate提供了多种便捷访问远程Http服务的方法,能够大大提高客户端的编写效率
OkHttpOkHttp是一个高效的HTTP客户端

HttpClient

(1)实现了所有 HTTP 的方法(GET,POST,PUT,HEAD 等)
(2)支持自动转向
(3)支持 HTTPS 协议
(4)支持代理服务器等

HTTPClient可以作为SOA架构的服务处理组件,在一些简单的服务请求上HttpClien它的小巧轻便可以解决服务之间请求的问题,相对于Dobbo框架来说HttpClient可以轻便的实现服务器之间的相互调用;但是在大型的项目中HttpClient就显得不如Dubbo框架

RestTemplate

从Spring 3.0开始支持的一个HTTP请求工具,提供了常见的REST请求方案的模版。提供了用于访问Http请求的客户端,RestTemple提供了多种简洁的远程访问服务的方法,省去了很多无用的代码(提供了六种常用的HTTP方法实现远程服务调用)

OkHttp

(1)OkHttp是一个高效的HTTP客户端,允许所有同一个主机地址的请求共享同一个socket连接;连接池减少请求延时;透明的GZIP压缩减少响应数据的大小;缓存响应内容,避免一些完全重复的请求
(2)当网络出现问题的时候OkHttp依然坚守自己的职责,它会自动恢复一般的连接问题,如果你的服务有多个IP地址,当第一个IP请求失败时,OkHttp会交替尝试配置的其他IP,OkHttp使用现代TLS技术(SNI,ALPN)初始化新的连接,当握手失败时会回退到TLS 1.0


RestTemplate

从Spring 3.0开始支持的一个HTTP请求工具,提供了常见的REST请求方案的模版。提供了用于访问Http请求的客户端,RestTemple提供了多种简洁的远程访问服务的方法,省去了很多无用的代码(提供了六种常用的HTTP方法实现远程服务调用)

Spring框架提供的RestTemplate类可用于在应用中调用REST服务,简化了与http服务的通信方式,统一了REST风格的标准,封装了http链接,只需要传入url及返回值类型即可。相较于之前常用的HttpClient,RestTemplate是一种更优雅的调用RESTful服务的方式

在Spring应用程序中访问第三方REST服务与使用Spring RestTemplate类有关。RestTemplate类的设计原则与许多其他Spring模板类(JdbcTemplate、JmsTemplate)相同,为执行复杂任务提供了一种具有默认行为的简化方法

RestTemplate默认依赖JDK提供http连接的能力(HttpURLConnection),如果有需要的话也可以通过setRequestFactory()替换为例如Apache HttpComponents、Netty或OkHttp等其它HTTP library

RestTemplate类是为调用REST服务而设计的,因此它的主要方法与REST的基础紧密相连就不足为奇了,后者是HTTP协议的方法:HEAD、GET、POST、PUT、DELETE和OPTIONS。

例如:RestTemplate类具有headForHeaders()、getForObject()、postForObject()、put()和delete()等方法;GET、POST、PUT、DELETE以及一些通用的请求执行方法exchange以及execute。

RestTemplate继承自InterceptingHttpAccessor并且实现了RestOperations接口。RestOperations接口定义了基本的REST风格操作,这些操作在RestTemplate中都得到了实现


构造方法(3种)

RestTemplate有3个构造方法,一个无参构造,两个有参构造

(1)RestTemplate()

使用默认配置创建一个RestTemplate实例,默认的HttpMessageConverter集合被初始化

(2)RestTemplate(ClientHttpRequestFactory requestFactory)

使用指定的ClientHttpRequestFactory创建一个RestTemplate实例。

方法描述
requestFactory用于创建HTTP请求的工厂,默认的实现有SimpleClientHttpRequestFactory、HttpComponentsClientHttpRequestFactory

如果没有设置默认是SimpleClientHttpRequestFactory

(3)RestTemplate(List<HttpMessageConverter<?>> messageConverters)

传入自定义的HttpMessageConverter集合,并赋值给messageConverters,之后使用自定义的HttpMessageConverter


ClientHttpRequestFactory
Spring定义的一个接口,用于生产org.springframework.http.client.ClientHttpRequest对象,RestTemplate只是模板类,抽象了很多调用方法,而底层真正使用何种框架发送HTTP请求是通过ClientHttpRequestFactory指定的。

RestTemplate可以在构造时设置ClientHttpRequestFactory,也可以通过setRequestFactory()设置。

Spring的两种ClientHttpRequestFactory的实现类
SimpleClientHttpRequestFactory和HttpComponentsClientHttpRequestFactory

(1)SimpleClientHttpRequestFactory
如果什么都不设置,RestTemplate默认使用的是SimpleClientHttpRequestFactory,其内部使用的是JDK的java.net.HttpURLConnection创建底层连接,默认是没有连接池的,connectTimeout和readTimeout都是 -1,即没有超时时间

(2)HttpComponentsClientHttpRequestFactory
HttpComponentsClientHttpRequestFactory底层使用Apache HttpClient创建请求,访问远程的Http服务,可以使用一个已经配置好的HttpClient实例创建HttpComponentsClientHttpRequestFactory请求工厂,HttpClient实例中可以配置连接池和证书等信息


常用方法(11种)

在RestTemplate中定义了11个独立的操作

RestTemplate的方法名遵循一定的命名规范:第一部分表示用哪种HTTP方法调用(get、post),第二部分表示返回类型

方法描述
getForObject()发送GET请求,将HTTP response转换成一个指定的Object对象
postForEntity()发送POST请求,将给定的对象封装到HTTP请求体,返回类型是一个HttpEntity对象

每个HTTP方法对应的RestTemplate方法都有3种。其中2种的url参数为字符串,URI参数变量分别是Object数组和Map,另外一种url使用URI类型作为参数。

getForObject(String url, Class<T> responseType, Object... uriVariables)
getForObject(String url, Class<T> responseType, Map<String, ?> uriVariables)
getForObject(URI url, Class<T> responseType)

注意:使用字符串类型的url,默认会对url进行转义,如http://example.com/hotel list在执行时会转义http://example.com/hotel%20list,这样其实是没有问题的,但如果字符串类型的url本身已经转义过了,执行时就会再转义一次,变成http://example.com/hotel%2520list。如果不需要这种隐式的转义,可以使用java.net.URI参数的方法,这种方法不会在执行时存在隐式的url转义,可以在创建URI对象时自行决定是否转义,推荐使用UriComponentsBuilder创建

UriComponents uriComponents = UriComponentsBuilder.fromUriString(
        "http://example.com/hotels/{hotel}/bookings/{booking}")
        .build() 
        .expand("42", "21")
        .encode();
URI uri = uriComponents.toUri();
//build(true)就不会对url转义,但如果包含http://example.com/hotel list这种需要转义的url,会报错

exchange()和execute()比其它方法(如getForObject、postForEntity等)使用范围更广,允许调用者指定HTTP请求的方法(GET、POST、PUT等),并且可以支持像HTTP PATCH(部分更新),但需要底层的HTTP库支持,JDK自带的HttpURLConnection不支持PATCH方法,Apache的HTTPClient 4.2及以后版本支持。

方法描述
getForEntity()发送一个HTTP GET请求,返回的ResponseEntity包含了响应体所映射成的对象。比如:响应体数据为一个由User转化的json,那么它被封装进ResponseEntity时将转回User对象。用一个ResponseEntity对象接收该方法返回值后,可取出其中的响应体对象、响应头和响应状态
getForObject()发送一个HTTP GET请求,返回根据响应体映射形成的对象。同上,不过只返回User对象
postForEntity()POST数据到一个URL,返回的ResponseEntity包含了响应体所映射成的对象
postForObject()POST数据到一个URL,返回根据响应体映射形成的对象
postForLocation()POST数据到一个URL,返回新创建资源的URL
put()PUT资源到特定的URL
delete()在特定的URL上对资源执行HTTP DELETE操作
execute()在URL上执行特定的HTTP方法,返回一个从响应体映射得到的对象
exchange()在URL上执行特定的HTTP方法,返回的ResponseEntity包含了响应体所映射成的对象,这个对象是从响应体中映射得到的
headForHeaders()发送HTTP HEAD请求,返回包含特定资源URL的HTTP头
optionsForAllow()发送HTTP OPTIONS请求,返回对特定URL的Allow头信息

RestTemplate基本使用

RestTemplate发送的是HTTP请求,那么在响应的数据中必然也有响应头,如果开发者需要获取响应头的话,那么就需要使用getForEntity来发送HTTP请求,此时返回的对象是一个ResponseEntity的实例。这个实例中包含了响应数据以及响应头

构造方法参数

RestTemplate参数描述
urlString类型或URI类型的请求地址。请求的URL。表示要调用的服务的地址
responseType指定返回的实体类型(body),Class对象。负责承载数据的类
uriVariablesURI参数,可以是变长数组或map。类似预编译,为防止URL写死,为URL的参数赋值

返回值:responseType指定的Entity类型Object类型。ResponseEntity是Spring对HTTP响应的封装,包括了几个重要的元素。如响应码、contentType、contentLength、response header信息、response body信息等。返回的消息体的数据类型

返回值一般为第二参数Class<T>的类型。都是使用<T> T指定的返回值。


GET请求

在这里插入图片描述

(1)getForEntity

getForEntity()的返回值是一个ResponseEntity,ResponseEntity是Spring对HTTP请求响应的封装,包括了几个重要的元素:响应码、contentType、contentLength、响应消息体等。

@Autowired
private RestTemplate restTemplate;

@RequestMapping("/gethello")
public String getHello() {
	ResponseEntity<String> responseEntity = restTemplate.getForEntity("http://localhost:8080/hello", String.class);
	String body = responseEntity.getBody();
	HttpStatus statusCode = responseEntity.getStatusCode();
	int statusCodeValue = responseEntity.getStatusCodeValue();
	HttpHeaders headers = responseEntity.getHeaders();
	StringBuffer result = new StringBuffer();
	result.append("responseEntity.getBody()")
		.append(body)
		.append("<hr>")
		.append("responseEntity.getStatusCode():")
		.append(statusCode).append("<hr>").append("responseEntity.getStatusCodeValue():")
		.append(statusCodeValue).append("<hr>").append("responseEntity.getHeaders():").append(headers)
		.append("<hr>");
	return result.toString();
}

有时候在调用服务提供者提供的接口时,可能需要传递参数,有两种不同的方式,如下:

@Autowired
private RestTemplate restTemplate;

@RequestMapping("/sayhello")
public String sayHello() {
	ResponseEntity<String> responseEntity = restTemplate.getForEntity("http://localhost:8080/sayhello?name={1}",String.class, "张三");
	return responseEntity.getBody();
}

@RequestMapping("/sayhello2")
public String sayHello2() {
	Map<String, String> map = new HashMap<>();
	map.put("name", "李四");
	ResponseEntity<String> responseEntity = restTemplate.getForEntity("http://localhost:8080/sayhello?name={name}",
	String.class, map);
	return responseEntity.getBody();
}

可以用一个数字做占位符,最后是一个可变长度的参数,来一一替换前面的占位符,也可以前面使用name={name}这种形式,最后一个参数是一个map,map的key即为前边占位符的名字,map的value为参数值

第一个调用地址也可以是一个URI而不是字符串,这个时候我们构建一个URI即可,参数神马的都包含在URI中了,如下:

@Autowired
private RestTemplate restTemplate;

@RequestMapping("/sayhello3")
public String sayHello3() {
	UriComponents uriComponents = UriComponentsBuilder.fromUriString("http://HELLO-SERVICE/sayhello?name={name}")
		.build()
		.expand("王五")
		.encode();
	URI uri = uriComponents.toUri();
	ResponseEntity<String> responseEntity = restTemplate.getForEntity(uri, String.class);
	return responseEntity.getBody();
}

通过Spring中提供的UriComponents来构建Uri即可。
当然,服务提供者不仅可以返回String,也可以返回一个自定义类型的对象,比如我的服务提供者中有如下方法:

@Autowired
private RestTemplate restTemplate;

@RequestMapping(value = "/getbook1", method = RequestMethod.GET)
public Book book1() {
	return new Book("三国演义", 90, "罗贯中", "花城出版社");
}

对于该方法我可以在服务消费者中通过如下方式来调用:

@Autowired
private RestTemplate restTemplate;

@RequestMapping("/book1")
public Book book1() {
	ResponseEntity<Book> responseEntity = restTemplate.getForEntity("http://localhost:8080/getbook1", Book.class);
	return responseEntity.getBody();
}

(2)getForObject

getForObject函数实际上是对getForEntity函数的进一步封装,如果你只关注返回的消息体的内容,对其他信息都不关注,此时可以使用getForObject

@Autowired
private RestTemplate restTemplate;

@RequestMapping("/book2")
public Book book2() {
	Book book = restTemplate.getForObject("http://localhost:8080/getbook1", Book.class);
	return book;
}

POST请求

在RestTemplate中,POST请求可以通过如下三个方法来发起:

在这里插入图片描述

(1)postForEntity

该方法和get请求中的getForEntity方法类似,如下例子:

@Autowired
private RestTemplate restTemplate;

@RequestMapping("/book3")
public Book book3() {
	Book book = new Book();
	book.setName("红楼梦");
	ResponseEntity<Book> responseEntity = restTemplate.postForEntity("http://localhost:8080/getbook2", book, Book.class);
	return responseEntity.getBody();
}

这里创建了一个Book对象,这个Book对象只有name属性有值,将之传递到服务提供者那里去,服务提供者代码如下:

@Autowired
private RestTemplate restTemplate;

@RequestMapping(value = "/getbook2", method = RequestMethod.POST)
public Book book2(@RequestBody Book book) {
	book.setPrice(33);
	book.setAuthor("曹雪芹");
	book.setPublisher("人民文学出版社");
	return book;
}

服务提供者接收到服务消费者传来的参数book,给其他属性设置上值再返回,调用结果如下:


(2)postForObject

如果你只关注,返回的消息体,可以直接使用postForObject。用法和getForObject一致。


(3)postForLocation

postForLocation也是提交新资源,提交成功之后,返回新资源的URI,postForLocation的参数和前面两种的参数基本一致,只不过该方法的返回值为Uri,这个只需要服务提供者返回一个Uri即可,该Uri表示新资源的位置


PUT请求

在RestTemplate中,PUT请求可以通过put方法调用,put方法的参数和前面介绍的postForEntity方法的参数基本一致,只是put方法没有返回值而已。举一个简单的例子,如下:

@Autowired
private RestTemplate restTemplate;

@RequestMapping("/put")
public void put() {
	Book book = new Book();
	book.setName("红楼梦");
	restTemplate.put("http://HELLO-SERVICE/getbook3/{1}", book, 99);
}

Book对象是要提交的参数,最后的99用来替换前面的占位符{1}


DELETE请求

delete请求我们可以通过delete方法调用来实现,如下例子:

@Autowired
private RestTemplate restTemplate;

@RequestMapping("/delete")
public void delete() {
	restTemplate.delete("http://HELLO-SERVICE/getbook4/{1}", 100);
}

delete方法也有几个重载的方法,不过重载的参数和前面基本一致


exchange方法

(1)可以支持多种HTTP方法,在参数中指定。提供统一的方法模板进行四种请求:POST、PUT、DELETE、GET
(2)可以在请求中增加header和body信息,返回类型是ResponseEntity,可以从中获取响应的状态码,header和body等信息

exchange(String url,
				HttpMethod method, 
				@Nullable HttpEntity<?> requestEntity,
				ParameterizedTypeReference<T> responseType, 
				Map<String, ?> uriVariables);
参数描述
url请求地址
method请求类型(如:POST、PUT、DELETE、GET)
requestEntity请求实体。封装请求头,请求内容
responseType响应类型。根据服务接口的返回类型决定
uriVariablesurl中参数变量值
@Autowired
private RestTemplate restTemplate;

HttpHeaders requestHeaders = new HttpHeaders();
requestHeaders.set("MyRequestHeader", "MyValue");
HttpEntity requestEntity = new HttpEntity(requestHeaders);
HttpEntity<String> response = restTemplate.exchange(
	        "http://example.com/hotels/{hotel}",
	        HttpMethod.GET,     // GET请求
	        requestEntity,      // requestEntity,可以设置请求header、body
	        String.class, "42");
// 响应头信息
String responseHeader = response.getHeaders().getFirst("MyResponseHeader");
String body = response.getBody();
  • 0
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

未禾

您的支持是我最宝贵的财富!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值