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请求:
    在这里插入图片描述


–欢迎评论区留言讨论,转载请注明出处。

RestTemplate 是一个 Spring 框架中的类,可以用于发送 HTTP 请求。在使用 RestTemplate 时,我们可能需要设置自定义的请求头,以传递自定义信息或实现特定功能。以下是 RestTemplate 设置请求头的方法: 1. 使用 HttpHeaders 类添加请求头 可以通过创建 HttpHeaders 对象,然后添加请求头信息来设置请求头。例如: HttpHeaders headers = new HttpHeaders(); headers.set("Authorization", "Basic " + encodeCredentials("username", "password")); HttpEntity<String> entity = new HttpEntity<>(headers); 在这个例子中,我们设置了一个名为 Authorization 的请求头,值为经过 Base64 编码的用户名和密码。这个请求头用于进行身份认证。 2. 使用 RestTemplate 的 exchange 方法设置请求RestTemplate 的 exchange 方法可以接收一个 RequestEntity 对象,该对象包含了请求体和请求头。例如: HttpHeaders headers = new HttpHeaders(); headers.set("Accept", MediaType.APPLICATION_JSON_VALUE); RequestEntity<Object> requestEntity = new RequestEntity<>(headers, HttpMethod.GET, new URI(url)); ResponseEntity<String> response = restTemplate.exchange(requestEntity, String.class); 在这个例子中,我们设置了一个名为 Accept 的请求头,值为 application/json,用于指定预期的响应类型为 JSON。 3. 使用 RestTemplate 的 interceptors 设置全局请求RestTemplate 的 interceptors 是一组拦截器,可以在发送请求前或收到响应后对请求进行处理。通过扩展 ClientHttpRequestInterceptor,我们可以定义一个拦截器,在每次请求中添加自定义请求头。例如: public class CustomHeaderInterceptor implements ClientHttpRequestInterceptor { @Override public ClientHttpResponse intercept( HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException { HttpHeaders headers = request.getHeaders(); headers.add("Custom-Header", "foo"); return execution.execute(request, body); } } RestTemplate restTemplate = new RestTemplateBuilder() .additionalInterceptors(new CustomHeaderInterceptor()) .build(); 在这个例子中,我们定义了一个名为 Custom-Header 的请求头,值为 foo,并将这个拦截器添加到 RestTemplate 中。每次请求时都会自动添加这个请求头。 总而言之,RestTemplate 可以通过 HttpHeaders 类、exchange 方法或拦截器实现自定义请求头的设置,以满足各种场景下的需求。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

zhuzicc

你的鼓励将是我创作的最大动力

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

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

打赏作者

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

抵扣说明:

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

余额充值