1、restTemplate超时配置
通过定义ClientHttpRequestFactory工厂并配置超时时间初始化restTemplate。RestTemplate默认也是用的ClientHttpRequestFactory的。
public RestTemplate iRestTemplate() {
SimpleClientHttpRequestFactory httpClientFactory= new SimpleClientHttpRequestFactory();
httpClientFactory.setConnectTimeout(2000);
httpClientFactory.setReadTimeout(10000);
return new RestTemplate(httpClientFactory);
}
2、支持连接池配置
默认的ClientHttpRequestFactory使用的是HttpUrlConnection,本身不支持连接池。当需要启用连接池提高吞吐量或者减少请求响应时间,替换掉默认的ClientHttpRequestFactory,如Apache HttpComponents HttpClient。
@Bean
public RestTemplate restTemplate(@Qualifier("clientHttpRequestFactory") ClientHttpRequestFactory factory) {
RestTemplate restTemplate = new RestTemplate(factory);
restTemplate.getMessageConverters().set(1,
new StringHttpMessageConverter(Charset.forName("UTF-8")));
return restTemplate;
}
@Bean(name = "clientHttpRequestFactory")
public ClientHttpRequestFactory clientHttpRequestFactory(HttpClient client) {
HttpComponentsClientHttpRequestFactory clientHttpRequestFactory = new
HttpComponentsClientHttpRequestFactory(client);
clientHttpRequestFactory.setConnectTimeout(httpClientProperties.getConnectTimeout());
clientHttpRequestFactory.setReadTimeout(httpClientProperties.getReadTimeout());
clientHttpRequestFactory.setConnectionRequestTimeout(httpClientProperties.getAcquireConnectionTimeout());
return clientHttpRequestFactory;
}
@Bean
public HttpClient httpClient() {
HttpClientBuilder httpClientBuilder = HttpClientBuilder.create();
try {
// 针对https协议相关配置
SSLContext sslContext = SSLContext.getInstance("SSL");// 获取一个SSLContext实例
TrustManager[] trustAllCerts = {new InsecureTrustManager()};
sslContext.init(null, trustAllCerts, new java.security.SecureRandom());// 初始化SSLContext实例
//设置信任ssl访问
httpClientBuilder.setSSLContext(sslContext);
HostnameVerifier hostnameVerifier = NoopHostnameVerifier.INSTANCE;
SSLConnectionSocketFactory sslConnectionSocketFactory = new SSLConnectionSocketFactory(sslContext, hostnameVerifier);
Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory>create()
// 注册http和https请求
.register("http", PlainConnectionSocketFactory.getSocketFactory())
.register("https", sslConnectionSocketFactory).build();
PoolingHttpClientConnectionManager poolingHttpClientConnectionManager = new PoolingHttpClientConnectionManager(socketFactoryRegistry);
poolingHttpClientConnectionManager.setMaxTotal(httpClientProperties.getMaxConnection());
poolingHttpClientConnectionManager.setDefaultMaxPerRoute(httpClientProperties.getMaxConnectionRoute());
httpClientBuilder.setConnectionManager(poolingHttpClientConnectionManager);
httpClientBuilder.setRetryHandler(new DefaultHttpRequestRetryHandler(httpClientProperties.getRetryTimes(), true));
//设置默认请求头
List<Header> headers = getDefaultHeaders();
httpClientBuilder.setDefaultHeaders(headers);
httpClientBuilder.evictExpiredConnections();
httpClientBuilder.evictIdleConnections(httpClientProperties.getIdleTime(), TimeUnit.MINUTES);
CloseableHttpClient httpClient = httpClientBuilder.build();
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
try {
httpClient.close();
} catch (IOException e) {
log.error("close http client error.", e);
}
}));
return httpClient;
} catch (Exception e) {
log.error("HttpClient create error.", e);
}
return null;
}
private List<Header> getDefaultHeaders() {
List<Header> headers = new ArrayList<>();
headers.add(new BasicHeader("Connection", "Keep-Alive"));
return headers;
}
class InsecureTrustManager implements X509TrustManager {
@Override
public void checkServerTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {}
@Override
public void checkClientTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {}
/**
* 返回受信任的X509证书数组
*/
@Override
public X509Certificate[] getAcceptedIssuers() {
return null;
}
}
public class HttpClientProperties {
private int readTimeout;
private int connectTimeout;
private int acquireConnectionTimeout;
private int maxConnection;
private int maxConnectionRoute;
private int retryTimes;
private int idleTime;
}
3、响应状态错误码处理
默认实现,如果是4xx或者5xx,请求响应的时候会抛出异常:
/**
* org.springframework.web.client.DefaultResponseErrorHandler#handleError()
*/
protected void handleError(ClientHttpResponse response, HttpStatus statusCode) throws IOException {
String statusText = response.getStatusText();
HttpHeaders headers = response.getHeaders();
byte[] body = getResponseBody(response);
Charset charset = getCharset(response);
String message = getErrorMessage(statusCode.value(), statusText, body, charset);
switch (statusCode.series()) {
case CLIENT_ERROR:
throw HttpClientErrorException.create(message, statusCode, statusText, headers, body, charset);
case SERVER_ERROR:
throw HttpServerErrorException.create(message, statusCode, statusText, headers, body, charset);
default:
throw new UnknownHttpStatusCodeException(message, statusCode.value(), statusText, headers, body, charset);
}
}
在一些场景中,某些接口可能会通过不同的状态码来返回不同的错误信息,不是返回200的状态码,在消息体使用code等字段来标识,如果是4xx或者5xx的时候不希望抛异常,而由我们自己获取判断处理,可以如下方式定义:
@Bean
public RestTemplate restTemplate() {
RestTemplate restTemplate = new RestTemplate();
restTemplate.getMessageConverters().set(1,
new StringHttpMessageConverter(Charset.forName("UTF-8")));
restTemplate.setErrorHandler(new ResponseErrorHandler() {
@Override
public boolean hasError(ClientHttpResponse response) throws IOException {
return false;
}
@Override
public void handleError(ClientHttpResponse response) throws IOException {
}
});
return restTemplate;
}