如何在HandlerInterceptor中读取请求体?

2023-12-05

我有 Spring Boot,我需要在数据库中记录用户操作,所以我编写了 HandlerInterceptor:

@Component
public class LogInterceptor implements HandlerInterceptor {
@Autovired
private LogUserActionService logUserActionService;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) 
throws IOException {
    String userName = SecurityContextHolder.getContext().getAuthentication().getName();
    String url = request.getRequestURI();
    String queryString = request.getQueryString() != null ? request.getQueryString() : "";
    String body = "POST".equalsIgnoreCase(request.getMethod()) ? new BufferedReader(new InputStreamReader(request.getInputStream())).lines().collect(Collectors.joining(System.lineSeparator())) : queryString;
    logUserActionService.logUserAction(userName, url, body);
    return true;
}
}

但根据这个答案在HandlerInterceptor中获取RequestBody和ResponseBody“RequestBody 只能读取一次”,所以据我了解,我读取输入流,然后 Spring 尝试执行相同的操作,但流已被读取,并且我收到错误:“缺少所需的请求正文...”

所以我尝试了不同的方法来制作缓冲输入流,即:

HttpServletRequest httpServletRequest = new ContentCachingRequestWrapper(request);
new BufferedReader(new InputStreamReader(httpServletRequest.getInputStream())).lines().collect(Collectors.joining(System.lineSeparator()))

Or

InputStream bufferedInputStream = new BufferedInputStream(request.getInputStream());

但没有任何帮助 我也尝试使用

@ControllerAdvice
public class UserActionRequestBodyAdviceAdapter extends RequestBodyAdviceAdapter {

但它只有正文,没有 URL 或请求参数等请求信息 也尝试使用过滤器,但结果相同。

因此,我需要一种好方法来从请求中获取信息,例如用户、URL、参数、正文(如果存在)并将其写入数据库。


要记录 HTTP 请求和响应,您可以使用RequestBodyAdviceAdapter and ResponseBodyAdvice。在这里,它按照我的方式使用。

CustomRequestBodyAdviceAdapter.java

@ControllerAdvice
public class CustomRequestBodyAdviceAdapter extends RequestBodyAdviceAdapter {

    @Autowired
    HttpServletRequest httpServletRequest;

    @Override
    public boolean supports(MethodParameter methodParameter, Type type, Class<? extends HttpMessageConverter<?>> aClass) {
        return true;
    }

    @Override
    public Object afterBodyRead(Object body, HttpInputMessage inputMessage, MethodParameter parameter, Type targetType,
            Class<? extends HttpMessageConverter<?>> converterType) {

        // here you can full log httpServletRequest and body.

        return super.afterBodyRead(body, inputMessage, parameter, targetType, converterType);
    }
}

CustomResponseBodyAdviceAdapter.java

@ControllerAdvice
public class CustomResponseBodyAdviceAdapter implements ResponseBodyAdvice<Object> {

    @Autowired
    private LoggingService loggingService;

    @Override
    public boolean supports(MethodParameter methodParameter, Class<? extends HttpMessageConverter<?>> aClass) {
        return true;
    }

    @Override
    public Object beforeBodyWrite(Object o, MethodParameter methodParameter, MediaType mediaType,
            Class<? extends HttpMessageConverter<?>> aClass, ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse) {
        if (serverHttpRequest instanceof ServletServerHttpRequest && serverHttpResponse instanceof ServletServerHttpResponse) {

            // here you can full log httpServletRequest and body.
        }
        return o;
    }
}

Above AdviceAdapter无法处理GET要求。所以,你可以使用HandlerInterceptor.

CustomWebConfigurerAdapter.java

@Component
public class CustomWebConfigurerAdapter implements WebMvcConfigurer {

   @Autowired
   private CustomLogInterceptor httpServiceInterceptor;

   @Override
   public void addInterceptors(InterceptorRegistry registry) {
      registry.addInterceptor(httpServiceInterceptor);
   }
}

CustomLogInterceptor.java

@Component
public class CustomLogInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
        if (DispatcherType.REQUEST.name().equals(request.getDispatcherType().name()) && request.getMethod().equals(HttpMethod.GET.name())) {

            // here you can full log httpServletRequest and body for GET Request.

        }
        return true;
    }
}

在这里你可以参考我的 git 中的完整源代码。

spring boot-http-request-response-logging-with-json-logger

+功能=>它已经与ELK(Elasticsearch、Logstash、Kibana)

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何在HandlerInterceptor中读取请求体? 的相关文章

随机推荐