Spring在Filter中记录Web请求Request和返回Response的内容及时长()

  本篇文章为你整理了Spring在Filter中记录Web请求Request和返回Response的内容及时长()的详细内容,包含有 Spring在Filter中记录Web请求Request和返回Response的内容及时长,希望能帮助你了解 Spring在Filter中记录Web请求Request和返回Response的内容及时长。

  在Spring MVC中,我们有时需要记录一下请求和返回的内容,方便出现问题时排查。比较Header、Request Body等。这些在Controller也可以记录,但在Filter中会更方便。而我们使用的是OncePerRequestFilter。

  2 记录请求

  2.1 流重复读的问题

  可以通过下面的代码来读取请求Body:

  

byte[] requestBody = StreamUtils.copyToByteArray(request.getInputStream());

 

  log.info("request body = {}", new String(requestBody, StandardCharsets.UTF_8));

  

 

  但是这里从流读取了一次内容后,后续不可再读了。这就造成了真正处理请求的时候,报错失败,我们需要把Request对象改造成可重复读的类。

  2.2 通过Wrapper解决流重复读的问题

  为了可以让流重复读,加了以下Wrapper:

  

public class PkslowRequestWrapper extends HttpServletRequestWrapper {

 

   private final byte[] body;

   public PkslowRequestWrapper(HttpServletRequest request) throws IOException {

   super(request);

   body = StreamUtils.copyToByteArray(request.getInputStream());

   @Override

   public ServletInputStream getInputStream() throws IOException {

   ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(body);

   return new ServletInputStream() {

   @Override

   public int read() throws IOException {

   return byteArrayInputStream.read();

   @Override

   public boolean isFinished() {

   return true;

   @Override

   public boolean isReady() {

   return true;

   @Override

   public void setReadListener(ReadListener readListener) {

   @Override

   public BufferedReader getReader() throws IOException {

   return new BufferedReader(new InputStreamReader(getInputStream()));

  

 

  这里主要在构造时读了流,然后存在变量body里,每次返回流的时候从body构造回去即可。

  在Filter中使用这个Wrapper如下:

  

PkslowRequestWrapper request = new PkslowRequestWrapper(req);

 

  ServletInputStream servletInputStream = request.getInputStream();

  String body = StreamUtils.copyToString(servletInputStream, Charset.defaultCharset());

  log.info("Request Body(PkslowRequestWrapper): {}", body);

  

 

  2.3 内置Filter

  其实,针对Request,Spring Boot提供了内置的Filter可以直接记录请求,使用如下:

  

package com.pkslow.springboot.common.web.config;

 

  import org.springframework.context.annotation.Bean;

  import org.springframework.context.annotation.Configuration;

  import org.springframework.web.filter.CommonsRequestLoggingFilter;

  @Configuration

  public class PkslowConfig {

   @Bean

   public CommonsRequestLoggingFilter loggingFilter() {

   CommonsRequestLoggingFilter filter = new CommonsRequestLoggingFilter();

   filter.setIncludeHeaders(true);

   filter.setIncludeClientInfo(true);

   filter.setIncludePayload(true);

   filter.setIncludeQueryString(true);

   filter.setAfterMessagePrefix("CommonsRequestLoggingFilter Request: ");

   return filter;

  

 

  但要开debug级别的日志才会打出来。

  

logging:

 

   level:

   root: debug

  

 

  日志如下:

  

DEBUG 20356 --- [nio-8080-exec-1] o.s.w.f.CommonsRequestLoggingFilter : Before request [POST /hello/pkslow, client=127.0.0.1, headers=[authorization:"Basic xxxxxx", content-length:"37", host:"localhost:8080", connection:"Keep-Alive", user-agent:"Apache-HttpClient/4.5.13 (Java/17.0.5)", accept-encoding:"gzip,deflate", Content-Type:"application/json;charset=UTF-8"]]

 

  

 

  3 记录返回

  返回也是一样,有流不可重复读的问题,使用Spring自带的ContentCachingResponseWrapper即可。

  

ContentCachingResponseWrapper response = new ContentCachingResponseWrapper(res);

 

  log.info("Response Code: {}", response.getStatus());

  String responseBody = new String(response.getContentAsByteArray(), response.getCharacterEncoding());

  log.info("Response Body: {}", responseBody);

  response.copyBodyToResponse();

  

 

  特别注意一定要调用copyBodyToResponse()这个方法,不然无法返回body给请求端了。

  4 记录时间

  记录整个请求的处理时间请参考: Java如何测量方法执行时间

  测试一下:

  

POST http://localhost:8080/hello/pkslow

 

  Content-Type: application/json

  Authorization: Basic xxxxxx

   "id": 999,

   "value": "content"

  

 

  执行日志结果如下:

  也可使用ContentCachingRequestWrapper来解决请求流不可重复读的问题,但这个Wrapper是有限制的,具体可以看它源码。也有人提了Issue。

  代码请看GitHub: https://github.com/LarryDpk/pkslow-samples

  以上就是Spring在Filter中记录Web请求Request和返回Response的内容及时长()的详细内容,想要了解更多 Spring在Filter中记录Web请求Request和返回Response的内容及时长的内容,请持续关注盛行IT软件开发工作室。

郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。

留言与评论(共有 条评论)
   
验证码: