RestTemplate 日志打印

发布时间 2023-09-14 15:00:42作者: 临渊不羡渔

思路

为 RestTemplate 添加一个拦截器,发送请求前打印请求相关日志,发送请求后打印响应结果. 由于 InputStream 按照规范只能读取一次,初始想法是打印结果后重新构建一个 ClientHttpResponse 对象返回. 无意发现 BufferingClientHttpResponseWrapper 读取 response 的时候,他会将其缓存在自己对象,达到支持重复读的效果,使用方式只需以 BufferingClientHttpRequestFactory 将自己原来的 http客户端工厂包装一层即可.

okhttp 依赖引入

<dependency>
	<groupId>com.squareup.okhttp3</groupId>
	<artifactId>okhttp</artifactId>
	<version>4.11.0</version>
</dependency>

RestTemplate 配置类


import lombok.extern.slf4j.Slf4j;
import okhttp3.ConnectionPool;
import okhttp3.OkHttpClient;
import org.apache.commons.io.IOUtils;
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.MediaType;
import org.springframework.http.client.*;
import org.springframework.web.client.RestTemplate;

import java.nio.charset.StandardCharsets;
import java.util.concurrent.TimeUnit;

@Slf4j
@Configuration
public class RestTemplateConfig {
    @Bean
    public RestTemplate restTemplate(RestTemplateBuilder builder) {
        return builder
                .requestFactory(this::httpRequestFactory)
                .additionalInterceptors(loggingRequestInterceptor())
                .build();
    }

    /**
     * 日志打印
     *
     * @return 自定义 http 请求拦截器
     */
    public ClientHttpRequestInterceptor loggingRequestInterceptor() {
        return (request, body, execution) -> {
            log.debug("request_uri          : \t{}", request.getURI());
            log.debug("request_method       : \t{}", request.getMethod());
            log.debug("request_headers      : \t{}", request.getHeaders());
            log.debug("request_body         : \t{}", new String(body, StandardCharsets.UTF_8));
            ClientHttpResponse response = execution.execute(request, body);
            log.debug("response_status      : \t{}", response.getStatusText());
            log.debug("response_headers     : \t{}", response.getHeaders());
            MediaType contentType = response.getHeaders().getContentType();
            if (MediaType.APPLICATION_JSON == contentType || MediaType.APPLICATION_JSON_UTF8 == contentType) {
                log.debug("response_body        : \t{}", IOUtils.toString(response.getBody(), StandardCharsets.UTF_8));
            } else {
                log.debug("response_content_type is not application/json");
            }
            return response;
        };
    }

    public ClientHttpRequestFactory httpRequestFactory() {
        OkHttpClient.Builder builder = new OkHttpClient()
                .newBuilder()
                .readTimeout(600, TimeUnit.SECONDS)
                .writeTimeout(10, TimeUnit.SECONDS)
                .connectTimeout(1, TimeUnit.SECONDS);
        builder.setConnectionPool$okhttp(new ConnectionPool(500, 30, TimeUnit.SECONDS));
        // 如果不像引入 okhttp ,可以使用 SimpleClientHttpRequestFactory
        // return new BufferingClientHttpRequestFactory(new SimpleClientHttpRequestFactory());
        return new BufferingClientHttpRequestFactory(new OkHttp3ClientHttpRequestFactory(builder.build()));

    }
}