SpringBoot之三:Web客户端

Web客户端主要有2种,一种是RestTemplate,另一种是Reactor方式的WebClient,这里我们就RestTemplate方式进行梳理

基本使用

注入

redisTemplate等不同,SpringBoot没有直接提供RedisTemplate的直接注入使用,但它却提供了RestTemplateAutoConfiguatrion,也提供了RestTemplateBuilder,用于生成RestTemplate。这样注入就需要自己通过bean的方式注入。

@Bean
public RestTemplate restTemplate(RestTemplateBuilder builder) {
	return builder.build();
}

ps:在仅使用RestTemplate而不适用web容器的情况下,可以通过WebApplicationType.NONE进行配置

基本接口

函数说明
getForEntity返回的ResponseEntity包含了响应体所映射成的对象
getForObject返回的请求体将映射为一个对象
postForEntityPOST 数据,返回包含一个对象的ResponseEntity
postForObjectPOST 数据,返回根据响应体匹配形成的对象
putPUT 资源到特定的URL
delete在特定的URL上对资源执行HTTP DELETE操作
exchange在URL上执行特定的HTTP方法,返回包含对象的ResponseEntity
// getForEntity
ResponseEntity<User> response = restTemplate.getForEntity("http://localhost/get/{id}", User.class, id);
User user = response.getBody();

// getForObject
 User user = restTemplate.getForObject("http://localhost/get/{id}", User.class, id);

// postForEntity
 ResponseEntity<String> response = restTemplate.postForEntity("http://localhost/save", user, String.class);
 String body = response.getBody();

// postForObject
 String body = restTemplate.postForObject("http://localhost/save", user, String.class);


URI构造

一般采用UriComponentsBuilder进行构建

URI uri = UriComponentsBuilder
				.fromUriString("http://example.com/hotels/{hotel}?id={id}")
				.build("Westin", "1");
ResponseEntity<Coffee> c = restTemplate.getForEntity(uri, Hotel.class);

在一些测试环境下,可以采用MvcUriComponentsBuilder

UriComponents uriComponents =  MvcUriComponentsBuilder.fromMethodCall(
                on(AddressController.class).getAddressesForCountry("US")).buildAndExpand(1);
URI uri = uriComponents.encode().toUri()

高级使用

如果需要传Header,就需要使用exchange(),这个方法中可以执行CRUD等各种方法,get、post等请求是基于execute、而execute基于doExecute;exchange是直接基于doExecute的。

另外这里就需要用的RequestEntity与ResponseEntity了。

在RequestEntity设置所需要的头,然后通过exchange()调用,最后返回ResponseEntity。

URI uri = UriComponentsBuilder
				.fromUriString("http://localhost:8080/coffee/?name={name}")
				.build("mocha");
RequestEntity<Void> req = RequestEntity.get(uri)
    .accept(MediaType.APPLICATION_XML)
    .build();
ResponseEntity<String> resp = restTemplate.exchange(req, String.class);

Get集合

不论getEntity、getObject、exchange获取时,都传入了一个class对象,对于getList的操作,需要传入的是ParameterizedTypeReference

ParameterizedTypeReference<List<Coffee>> ptr =new ParameterizedTypeReference<List<Coffee>>() {};
String coffeeUri = "http://localhost:8080/coffee/";
ResponseEntity<List<Coffee>> list = restTemplate.exchange(coffeeUri, HttpMethod.GET, null, ptr);

这个使用的是exchange的重载函数null参数为RequestEntity。

定制

RestTemplate支持的HTTP库

RestTemplate支持多种不同的Http客户端库,它们统一的接口是ClientHttpRequestFactory

包括:

  • SimpleClientHttpRequestFactory【默认】

  • HttpComponentsClientHttpRequestFactory

    ApacheHttpComponets

  • OkHttp3ClientHttpRequestFactory

    OkHttp,OkHttp支持了Http2的实现

下边主要使用HttpComponentsClientHttpRequestFactory来进行配置

底层的参数

  • 连接池

    PoolingHttpClientConnectionManager

  • KeepAlive策略

    这里根据response中Keep-Alive设置的timeout进行设置,如果没设置,默认30s。

    public class CustomConnectionKeepAliveStrategy implements ConnectionKeepAliveStrategy {
        private final long DEFAULT_SECONDS = 30;
    
        @Override
        public long getKeepAliveDuration(HttpResponse response, HttpContext context) {
            return Arrays.asList(response.getHeaders(HTTP.CONN_KEEP_ALIVE))
                .stream()
                .filter(h -> StringUtils.equalsIgnoreCase(h.getName(), "timeout")
                        && StringUtils.isNumeric(h.getValue()))
                .findFirst()
                .map(h -> NumberUtils.toLong(h.getValue(), DEFAULT_SECONDS))
                .orElse(DEFAULT_SECONDS) * 1000;
        }
    }
    

    Spring提供了DefaultConnectionKeepAliveStrategy,在这里有 Keep-Alive 认里面的值,没有的话永久有效。这里定制的对没有进行了调整。

  • 超时设置

    通过setConnectTimeout与setReadTimeout对连接超时、读取超时进行设置,防止客户端受到网络问题的影响

  • 禁用自动重试

    由于幂等的要求自动重试会造成不必要的麻烦,这里也进行了禁用disableAutomaticRetries

代码:


	@Bean
	public HttpComponentsClientHttpRequestFactory requestFactory() {
		PoolingHttpClientConnectionManager connectionManager =
				new PoolingHttpClientConnectionManager(30, TimeUnit.SECONDS);
		connectionManager.setMaxTotal(200);
		connectionManager.setDefaultMaxPerRoute(20);

		CloseableHttpClient httpClient = HttpClients.custom()
				.setConnectionManager(connectionManager)
				.evictIdleConnections(30, TimeUnit.SECONDS)
				.disableAutomaticRetries()
				.setKeepAliveStrategy(new CustomConnectionKeepAliveStrategy())
				.build();

		HttpComponentsClientHttpRequestFactory requestFactory =
				new HttpComponentsClientHttpRequestFactory(httpClient);

		return requestFactory;
	}

	@Bean
	public RestTemplate restTemplate(RestTemplateBuilder builder) {
		return builder
				.setConnectTimeout(Duration.ofMillis(100))
				.setReadTimeout(Duration.ofMillis(500))
				.requestFactory(this::requestFactory)
				.build();
	}
# spring 

评论

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×