Spring RestTemplate配置拦截器打印请求URL和响应结果
一、前言
最近项目中频繁调用第三方接口获取响应结果,请求方式post()和get(),调用过程中总是报400错误,就想到可能是提交的请求参数不对,但却没法看到RestTemplate的完整请求URL,所以想到配置拦截器,在发起Request请求时进行拦截打印,这样就方便查看发送的Request请求是否正确。
二、RestTemplateConfig配置类
@Slf4j
@Configuration
public class RestTemplateConfig {
private static final int HTTP_CLIENT_RETRY_COUNT = 3;
private static final int MAXIMUM_TOTAL_CONNECTION = 10;
private static final int MAXIMUM_CONNECTION_PER_ROUTE = 5;
private static final int CONNECTION_VALIDATE_AFTER_INACTIVITY_MS = 10 * 1000;
/**
* @param connectionTimeoutMs milliseconds/毫秒
* @param readTimeoutMs milliseconds/毫秒
* @return
*/
public static RestTemplate createRestTemplate(int connectionTimeoutMs, int readTimeoutMs,ObjectMapper objectMapper) {
HttpClientBuilder clientBuilder = HttpClients.custom();
PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager();
// 整个连接池最大连接数
connectionManager.setMaxTotal(MAXIMUM_TOTAL_CONNECTION);
// 设置每个路由的最大并发连接数,默认为2.
connectionManager.setDefaultMaxPerRoute(MAXIMUM_CONNECTION_PER_ROUTE);
// 官方推荐使用检查永久链接的可用性,而不推荐每次请求的时候才去检查 (milliseconds 毫秒)
connectionManager.setValidateAfterInactivity(CONNECTION_VALIDATE_AFTER_INACTIVITY_MS);
clientBuilder.setConnectionManager(connectionManager);
//设置重连操作次数,这里设置了3次
clientBuilder.setRetryHandler(new DefaultHttpRequestRetryHandler(HTTP_CLIENT_RETRY_COUNT, true, new ArrayList<>()) {
@Override
public boolean retryRequest(IOException exception, int executionCount, HttpContext context) {
HttpRequestWrapper httpRequestWrapper = (HttpRequestWrapper) context.getAttribute("http.request");
HttpRequest original = httpRequestWrapper.getOriginal();
log.info("Retry request, execution count:{}, exception:{}, request URL:{}", executionCount, exception.getMessage(), original);
return super.retryRequest(exception, executionCount, context);
}
});
//使用httpClient创建一个ClientHttpRequestFactory的实现
HttpComponentsClientHttpRequestFactory httpRequestFactory = new HttpComponentsClientHttpRequestFactory(clientBuilder.build());
httpRequestFactory.setConnectTimeout(connectionTimeoutMs);
httpRequestFactory.setConnectionRequestTimeout(readTimeoutMs);
httpRequestFactory.setReadTimeout(readTimeoutMs);
RestTemplate restTemplate = new RestTemplate(httpRequestFactory);
// 添加自定义拦截器
List<ClientHttpRequestInterceptor> interceptors = new ArrayList<ClientHttpRequestInterceptor>();
interceptors.add(new LoggingClientHttpRequestInterceptor());
restTemplate.setInterceptors(interceptors);
//提供对传出/传入流的缓冲,可以让响应body多次读取(如果不配置,拦截器读取了Response流,再响应数据时会返回body=null)
restTemplate.setRequestFactory(new BufferingClientHttpRequestFactory(httpRequestFactory));
MappingJackson2HttpMessageConverter messageConverter = restTemplate.getMessageConverters().stream().filter(MappingJackson2HttpMessageConverter.class::isInstance)
.map(MappingJackson2HttpMessageConverter.class::cast).findFirst().orElseThrow(() -> new RuntimeException("MappingJackson2HttpMessageConverter not found"));
messageConverter.setObjectMapper(objectMapper);
//防止响应中文乱码
restTemplate.getMessageConverters().stream().filter(StringHttpMessageConverter.class::isInstance).map(StringHttpMessageConverter.class::cast).forEach(a -> {
a.setWriteAcceptCharset(false);
a.setDefaultCharset(StandardCharsets.UTF_8);
});
return restTemplate;
}
@Bean
public RestTemplate restTemplate(){
RestTemplate restTemplate = RestTemplateConfig.createRestTemplate(5000, 5000, new ObjectMapper());
//配置自定义的interceptor拦截器
//使用restTemplate远程调用防止400和401导致报错而获取不到正确反馈信息
restTemplate.setErrorHandler(new DefaultResponseErrorHandler(){
@Override
public void handleError(ClientHttpResponse response) throws IOException {
if (response.getRawStatusCode() != 400 && response.getRawStatusCode() != 401){
super.handleError(response);
}
}
});
return restTemplate;
}
}
- 这里restTemplateConfig主要配置请求的超时时间、最大连接数、出现异常后重连次数、自定义拦截器添加等;
三、ClientHttpRequestInterceptor拦截器
- 需要去实现ClientHttpRequestInterceptor类中的intercept()方法才能实现Request拦截;
@Slf4j
public class LoggingClientHttpRequestInterceptor implements ClientHttpRequestInterceptor {
@Override
public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException {
tranceRequest(request, body);
ClientHttpResponse response = execution.execute(request, body);
traceResponse(response);
return response;
}
private void tranceRequest(HttpRequest request, byte[] body) throws UnsupportedEncodingException {
log.debug("=========================== request begin ===========================");
log.debug("uri : {}", request.getURI());
log.debug("method : {}", request.getMethod());
log.debug("headers : {}", request.getHeaders());
log.debug("request body : {}", new String(body, "utf-8"));
log.debug("============================ request end ============================");
}
private void traceResponse(ClientHttpResponse httpResponse) throws IOException {
StringBuilder inputStringBuilder = new StringBuilder();
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(httpResponse.getBody(), "UTF-8"));
String line = bufferedReader.readLine();
while (line != null) {
inputStringBuilder.append(line);
inputStringBuilder.append('\n');
line = bufferedReader.readLine();
}
log.debug("============================ response begin ============================");
log.debug("Status code : {}", httpResponse.getStatusCode());
log.debug("Status text : {}", httpResponse.getStatusText());
log.debug("Headers : {}", httpResponse.getHeaders());
log.debug("Response body: {}", inputStringBuilder.toString());
log.debug("============================= response end =============================");
}
}
四、lombok依赖(@Slf4j)
<!--Lombok-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.12</version>
</dependency>
五、效果展示
-
GET请求:
-
POST请求:
–欢迎评论区留言讨论,转载请注明出处。