介绍
在 Spring Boot 中使用 RestTemplate 发起 HTTP 请求时,记录请求和响应的日志可以帮助调试和监控应用程序的行为。Spring 提供了几种方式来记录这些信息,包括使用 Spring 的日志框架(如 SLF4J、Log4j、Logback 等)以及通过拦截器来增强 RestTemplate 的行为
具体实现
LoggingRequestInterceptor
拦截类
@Component("loggingRequestInterceptor")
public class LoggingRequestInterceptor implements ClientHttpRequestInterceptor {
Logger log = LoggerFactory.getLogger(getClass());
@Override
public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException {
traceRequest(request, body);
ClientHttpResponse response = execution.execute(request, body);
traceResponse(response);
return response;
}
private void traceRequest(HttpRequest request, byte[] body) throws IOException {
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 response) throws IOException {
StringBuilder inputStringBuilder = new StringBuilder();
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(response.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 : {}", response.getStatusCode());
log.debug("Status text : {}", response.getStatusText());
log.debug("Headers : {}", response.getHeaders());
log.debug("Response body: {}", inputStringBuilder.toString());
log.debug("=======================response end=================================================");
}
}
说明
- 日志记录:
- 使用 Logger 来记录请求和响应信息,这样可以更好地管理和查看日志。
- 使用 debug 级别记录,这意味着只有当日志级别设置为 DEBUG 或更低时,才会输出这些信息。
- 请求和响应追踪:
- traceRequest 方法用于记录请求的详细信息,包括 URI、HTTP 方法、请求头和请求体。
- traceResponse 方法用于记录响应的详细信息,包括状态码、状态文本、响应头和响应体。
- 编码:
- 使用 “UTF-8” 编码来读取请求体和响应体,确保字符编码的一致性。
HttpUtils
工具类
包含了一些基本的 HTTP 请求方法,用于发送 GET 和 POST 请求。
public class HttpUtils {
private RestTemplate restTemplate;
public void setRestTemplate(RestTemplate restTemplate) {
this.restTemplate = restTemplate;
}
/**
* @param : url
* @description: post请求 get
*/
public String sendGetRequest(String url) throws IOException {
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
HttpEntity httpEntity = new HttpEntity(headers);//请求体,包括请求数据 body 和 请求头 headers
ResponseEntity<String> strbody = restTemplate.exchange(url, HttpMethod.GET, httpEntity, String.class);
return strbody.getBody();
}
/**
* @param : url
* @param : data
* @description: post请求 json
*/
public String sendPostRequest(String url, JSONObject data) throws IOException {
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
HttpEntity httpEntity = new HttpEntity(data, headers);//请求体,包括请求数据 body 和 请求头 headers
ResponseEntity<String> strbody = restTemplate.exchange(url, HttpMethod.POST, httpEntity, String.class);
return strbody.getBody();
}
/**
* @param : url
* @param : data
* @description: post请求 json
*/
public String sendPostRequest(String url, String data) throws IOException {
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
HttpEntity httpEntity = new HttpEntity(data, headers);//请求体,包括请求数据 body 和 请求头 headers
ResponseEntity<String> strbody = restTemplate.exchange(url, HttpMethod.POST, httpEntity, String.class);
return strbody.getBody();
}
}
RestTemplateConfig
配置
在 Spring Boot 中配置 RestTemplate 并添加自定义的拦截器来记录请求和响应信息。
@Configuration
public class RestTemplateConfig {
/**
* 初始化连接工厂
* @return
*/
@Bean
public ClientHttpRequestFactory simpleClientHttpRequestFactory(){
SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory();
/**连接超时*/
factory.setConnectTimeout(15000);
/**读超时*/
factory.setReadTimeout(5000);
return factory;
}
/**
* 初始化请求模板
* @param simpleClientHttpRequestFactory
* @return
*/
@Bean
public RestTemplate restTemplate(ClientHttpRequestFactory simpleClientHttpRequestFactory,@Qualifier("loggingRequestInterceptor") LoggingRequestInterceptor loggingRequestInterceptor){
RestTemplate restTemplate = new RestTemplate(new BufferingClientHttpRequestFactory(simpleClientHttpRequestFactory));
List<ClientHttpRequestInterceptor> interceptors = new ArrayList<>();
interceptors.add(loggingRequestInterceptor);
restTemplate.setInterceptors(interceptors);
return restTemplate;
}
/**
* 返回请求工具类
* @param restTemplate
* @return
*/
@Bean
public HttpRequestUtils getHttpRequestUtils(RestTemplate restTemplate){
HttpRequestUtils httpRequestUtils = new HttpRequestUtils();
httpRequestUtils.setRestTemplate(restTemplate);
return httpRequestUtils;
}
}
说明
- 配置类 RestTemplateConfig:
- simpleClientHttpRequestFactory:初始化 SimpleClientHttpRequestFactory,设置连接超时时间和读取超时时间。
- restTemplate:初始化 RestTemplate,使用 BufferingClientHttpRequestFactory 包装
- simpleClientHttpRequestFactory,并设置自定义的拦截器 loggingRequestInterceptor。
- getHttpRequestUtils:返回一个自定义的工具类实例 HttpRequestUtils,并将配置好的 RestTemplate 传入。
- 拦截器 LoggingRequestInterceptor:
- 实现 ClientHttpRequestInterceptor 接口,用于记录请求和响应信息。
- 工具类 HttpRequestUtils:
- 包含一个 RestTemplate 成员变量,用于执行 HTTP 请求。
扩展
基于 ClientHttpRequestInterceptor 实现日志记录可以带来很多好处,特别是在调试、监控和审计 HTTP 请求方面。以下是一些主要用途
- 调试
- 请求详情:记录请求的详细信息,如请求 URL、HTTP 方法、请求头、请求体等,有助于定位问题所在。
- 响应详情:记录响应的状态码、响应头、响应体等信息,可以方便地查看后端服务的响应情况。
- 监控
- 性能指标:记录请求的时间戳,可以计算请求的耗时,从而监控系统的性能。
- 错误检测:记录请求和响应的状态码,有助于及时发现并处理错误请求。
- 审计
- 请求验证:记录请求内容,可以用于审计目的,确保请求符合预期的标准和规范。
- 安全审查:记录请求和响应内容,可以帮助检测潜在的安全问题,如敏感数据泄露等。
- 日志分析
- 流量统计:记录请求的数量和频率,可以分析系统的流量模式。
- API 使用情况:记录 API 的调用情况,可以了解各个 API 的使用频率和趋势。
- 错误处理
- 异常捕获:可以在请求和响应之间捕获异常,并记录详细的错误信息,方便后续排查问题。