思路
为 RestTemplate 添加一个拦截器,发送请求前打印请求相关日志,发送请求后打印响应结果. 由于 InputStream 按照规范只能读取一次,初始想法是打印结果后重新构建一个 ClientHttpResponse 对象返回. 无意发现 BufferingClientHttpResponseWrapper 读取 response 的时候,他会将其缓存在自己对象,达到支持重复读的效果,使用方式只需以 BufferingClientHttpRequestFactory 将自己原来的 http客户端工厂包装一层即可.
okhttp 依赖引入
| |
| <dependency> |
| <groupId>commons-io</groupId> |
| <artifactId>commons-io</artifactId> |
| <version>2.13.0</version> |
| </dependency> |
| <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(); |
| } |
| |
| |
| |
| |
| |
| |
| 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.isCompatibleWith(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)); |
| return new BufferingClientHttpRequestFactory(new OkHttp3ClientHttpRequestFactory(builder.build())); |
| |
| } |
| } |
| |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· 什么是nginx的强缓存和协商缓存
· 一文读懂知识蒸馏
· Manus爆火,是硬核还是营销?