在项目升级到springboot3.x后,官方提供的RestClient客户端是必须体验的。
那么,在实际生产中,我们经常会遇到一种情况,就行希望在日志里打印我们对第三方接口的请求参数和返回值,以便我们更好的调参和定位问题,那么,本文就让我们来了解一下,如何使用最新的spring6 restClient打印请求和响应日志。
其实,和springboot2.x时代,实现方案一样,还是通过spring的ClientHttpRequestInterceptor
扩展点来实现。
ClientHttpRequestInterceptor
是一个函数式接口,很简单:
1
| ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException;
|
其可以拦截RestClient对外请求的request请求体,body参数,以及发生的异常,同时还能拦截返回的Response结果。
所以,实现了这个接口,我们就可以同时获得请求实际发生时的参数情况和结果值了,打印日志的功能也就有了。
show code:
打印日志的实现类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79
| public class LoggingRequestInterceptor implements ClientHttpRequestInterceptor {
private static final Logger logger = LoggerFactory.getLogger(LoggingRequestInterceptor.class);
@Override public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException { logRequest(request, body); ClientHttpResponse response = new RepeatReadClientHttpRequestWrapper(execution.execute(request, body)); logResponse(response); return response; }
private void logRequest(HttpRequest request, byte[] body) { logger.debug("Request URI: {} {}",request.getMethod(), request.getURI()); logger.debug("Request Headers: {}", request.getHeaders()); if (body.length > 0) { logger.debug("Request Body: {}", new String(body, StandardCharsets.UTF_8)); } }
private void logResponse(ClientHttpResponse response) throws IOException { logger.debug("Response Code: {} , Headers: {}", response.getStatusCode(),response.getHeaders());
StringBuilder responseBody = new StringBuilder(); try (BufferedReader reader = new BufferedReader(new InputStreamReader(response.getBody(), StandardCharsets.UTF_8))) { String line; while ((line = reader.readLine()) != null) { responseBody.append(line); } } if (responseBody.length() > 0) { logger.debug("Response Body: {}", responseBody.toString()); } }
public class RepeatReadClientHttpRequestWrapper implements ClientHttpResponse { private ClientHttpResponse response; private byte[] bodyData = null;
public RepeatReadClientHttpRequestWrapper(ClientHttpResponse response) { this.response = response; }
@Override public HttpStatusCode getStatusCode() throws IOException { return response.getStatusCode(); }
@Override public String getStatusText() throws IOException { return response.getStatusText(); }
@Override public void close() { response.close(); }
@Override public InputStream getBody() throws IOException { if (Objects.isNull(bodyData)) { bodyData = response.getBody().readAllBytes(); } return new ByteArrayInputStream(bodyData); }
@Override public HttpHeaders getHeaders() { return response.getHeaders(); } } }
|
日志打印类实现后,还需要注入到RestClient客户端中才能实现,很简单:
还记得前文的RestClient的构建bean配置类吗?
1 2 3 4 5
| RestClient restClient = RestClient.builder() .baseUrl("http://localhost:8080/") .requestInterceptor(new LoggingRequestInterceptor()) .build();
|
结束,下班!
相关阅读
spring6.x使用@HttpExchange注解调用第三方接口