发布时间:2024-02-02 13:00
通常在Java代码中调用其它http 接口的话会使用HttpClient,不过这个使用起来有些繁琐,Spring中推出了一个简单的RestTemplate用来调用rest api,使用起来非常简单。
@RestController
@RequestMapping(\"/user\")
public class UserController {
@PostMapping(\"/regist\")
public User regist(@RequestBody CreateUserDTO param) {
return new User(1L, param.getUsername());
}
}
RestTemplate 使用起来非常简单,创建一个模板对象,直接调用接口接口。RestTemplate中的方法都是以请求方法来作为前缀。
String url = \"http://localhost:8080/user/regist\";
CreateUserDTO param = new CreateUserDTO(\"monday\", \"123456\");
RestTemplate restTemplate = new RestTemplate();
// 请求地址、请求参数、HTTP响应被转换成的对象类型
User user = restTemplate.postForObject(url, param, User.class);
System.out.println(user);
RestTemplate调用接口发送参数会将参数转为json,同样在处理响应时也是json格式。而RestTemplate中的接口接收的参数是对象,返回值类型也是对象,这就需要将参数转为json,将返回值转为对象,这就需要用到HTTP消息转换器了。默认情况下RestTemplate自动帮我们注册了一组HttpMessageConverter用来处理一些不同的contentType的请求。
com.alibaba
fastjson
1.2.74
FastJsonConfig fastJsonConfig=new FastJsonConfig();
fastJsonConfig.setSerializerFeatures(
SerializerFeature.QuoteFieldNames,
SerializerFeature.WriteMapNullValue,
SerializerFeature.DisableCircularReferenceDetect,
SerializerFeature.WriteDateUseDateFormat,
SerializerFeature.WriteNullStringAsEmpty);
List mediaTypeList=new ArrayList<>();
mediaTypeList.add(MediaType.APPLICATION_JSON);
FastJsonHttpMessageConverter fastJsonHttpMessageConverter = new FastJsonHttpMessageConverter();
fastJsonHttpMessageConverter.setSupportedMediaTypes(mediaTypeList);
fastJsonHttpMessageConverter.setFastJsonConfig(fastJsonConfig);
// 使用FastJsonHttpMessageConverter来处理json
RestTemplate restTemplate = new RestTemplate();
List> messageConverters = restTemplate.getMessageConverters();
messageConverters.remove(6);
messageConverters.add(fastJsonHttpMessageConverter);
我们在使用httpclient时都会配置一些参数,如最大连接数、连接超时时间、重试次数等。RestTemplate直接使用httpclient中的配置类来配置RestTemplate。
org.apache.httpcomponents
httpclient
// 长连接保持30秒
PoolingHttpClientConnectionManager pollingConnectionManager = new PoolingHttpClientConnectionManager(30, TimeUnit.SECONDS);
// 总连接数
pollingConnectionManager.setMaxTotal(1000);
// 同路由的并发数
pollingConnectionManager.setDefaultMaxPerRoute(1000);
HttpClientBuilder httpClientBuilder = HttpClients.custom();
httpClientBuilder.setConnectionManager(pollingConnectionManager);
// 重试次数,默认是3次,没有开启
httpClientBuilder.setRetryHandler(new DefaultHttpRequestRetryHandler(2, true));
// 保持长连接配置,需要在头添加Keep-Alive
httpClientBuilder.setKeepAliveStrategy(new DefaultConnectionKeepAliveStrategy());
List headers = new ArrayList<>();
headers.add(new BasicHeader(\"Accept-Encoding\", \"gzip,deflate\"));
headers.add(new BasicHeader(\"Accept-Language\", \"zh-CN\"));
headers.add(new BasicHeader(\"Connection\", \"Keep-Alive\"));
httpClientBuilder.setDefaultHeaders(headers);
HttpClient httpClient = httpClientBuilder.build();
// httpClient连接配置,底层是配置RequestConfig
HttpComponentsClientHttpRequestFactory clientHttpRequestFactory = new HttpComponentsClientHttpRequestFactory(httpClient);
// 指客户端和服务器建立连接的timeout,就是http请求的三个阶段,(1)建立连接(2)数据传送(3)断开连接,超时后会ConnectionTimeOutExceptioin。
clientHttpRequestFactory.setConnectTimeout(1000 * 10);
// 数据读取超时时间,即SocketTimeout
clientHttpRequestFactory.setReadTimeout(1000 * 40);
// 连接不够用的等待时间,不宜过长,必须设置,比如连接不够用时,时间过长将是灾难性的,指从连接池取连接的timeout
clientHttpRequestFactory.setConnectionRequestTimeout(500);
// 缓冲请求数据,默认值是true。通过POST或者PUT大量发送数据时,建议将此属性更改为false,以免耗尽内存。
clientHttpRequestFactory.setBufferRequestBody(true);
RestTemplate restTemplate = new RestTemplate(clientHttpRequestFactory);
拦截器可以在发出请求之前统一进行拦截,对请求进行修改,如增加请求头(如 timestamp、token)等。自定义拦截器需要实现ClientHttpRequestInterceptor接口。
public class HttpHeadInterceptor implements ClientHttpRequestInterceptor {
@Override
public ClientHttpResponse intercept(HttpRequest httpRequest, byte[] bytes, ClientHttpRequestExecution clientHttpRequestExecution) throws IOException {
String timestamp = String.valueOf(System.currentTimeMillis());
String body = new String(bytes);
String signature = body + timestamp + \"key\";
httpRequest.getHeaders().add(\"timestamp\", timestamp);
httpRequest.getHeaders().add(\"nonce\", UUID.randomUUID().toString());
httpRequest.getHeaders().add(\"sign\", MD5Encoder.encode(signature.getBytes()));
return clientHttpRequestExecution.execute(httpRequest, bytes);
}
}
// 添加拦截器
RestTemplate restTemplate = new RestTemplate();
restTemplate.getInterceptors().add(new HttpHeadInterceptor());