Spring prints http interface request and response

It is a basic technical requirement to print out the content of the interface request and response in the program log. If the log printing of the request response is implemented in each interface, the program writing will be very cumbersome. We can use the mechanism provided by spring to centrally process the log printing of the interface request response.
For specific code, refer to the sample project https://github.com/qihaiyan/springcamp/tree/master/spring-rest-log-request-response

I. Overview

Based on the mechanism provided by spring, there are three methods to print interface request response logs, namely CommonsRequestLoggingFilter, HandlerInterceptor, and RequestBodyAdviceAdapter.

2. Modify the log level print request parameters

By setting the log level of the web to DEBUG, spring will print the request parameters by itself. The content printed by this method covers the content of the log in all the methods described later. If you don’t need to do custom printing, and you don’t mind that the printed log level is DEBUG, it is enough.

logging:
  level:
    root: INFO
    web: DEBUG

3. Use CommonsRequestLoggingFilter to print request parameters

The use of CommonsRequestLoggingFilter is relatively simple, only need to implement a logFilter bean.
It's just that the log level of logFilter is debug, and the log level of the CommonsRequestLoggingFilter class needs to be set to debug level in the log configuration file.
At the same time, printing debug logs in the log files of the production environment does not conform to the specification.

@Bean
public CommonsRequestLoggingFilter logFilter() {
    
    
    CommonsRequestLoggingFilter loggingFilter = new CommonsRequestLoggingFilter();

    loggingFilter.setIncludeQueryString(true);
    loggingFilter.setIncludePayload(true);
    loggingFilter.setMaxPayloadLength(2048);

    return loggingFilter;
}

4. Use HandlerInterceptor to print request parameters

HandlerInterceptor can obtain the HttpServletRequest and HttpServletResponse information during the interface execution process, so it can print out the interface request response content.

@Component
public class LogInterceptorAdapter extends HandlerInterceptorAdapter {
    
    

    @Override
    public boolean preHandle(HttpServletRequest request,
                             HttpServletResponse response,
                             Object handler) {
    
    

        ServletRequest servletRequest = new ContentCachingRequestWrapper(request);
        Map<String, String[]> params = servletRequest.getParameterMap();

        // 从 request 中读取请求参数并打印
        params.forEach((key, value) -> log.info("logInterceptor " + key + "=" + Arrays.toString(value)));
        // 避免从 inputStream 中读取body并打印

        return true;
    }
}

There is a flaw in this method. For the application/json request parameters placed in the body, the content needs to be read through InputStream, and InputStream can only be read once. Once the InputStream
read operation is performed in HandlerInterceptor, Subsequent processing cannot read the contents of the InputStream, which is a very serious problem.
Therefore, HandlerInterceptor cannot be used to print the body in the request. This method can be modified to only print the get request parameters, and the post request parameters are printed using the RequestBodyAdviceAdapter method described below.

@Slf4j
@Component
public class LogInterceptorAdapter extends HandlerInterceptorAdapter {
    
    

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

            ServletRequest servletRequest = new ContentCachingRequestWrapper(request);
            Map<String, String[]> params = servletRequest.getParameterMap();

            // 从 request 中读取请求参数并打印
            params.forEach((key, value) -> log.info("logInterceptor " + key + "=" + Arrays.toString(value)));
            // 避免从 inputStream 中读取body并打印

        }
        return true;
    }
}

5. Use RequestBodyAdviceAdapter to print request parameters

RequestBodyAdviceAdapter encapsulates the afterBodyRead method, in which the content of the body can be obtained through the Object body parameter.

@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) {
    
    

        // 打印body内容

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

6. Use ResponseBodyAdvice to print the response content

Both ResponseBodyAdvice and RequestBodyAdviceAdapter belong to ControllerAdvice. ResponseBodyAdvice encapsulates the beforeBodyWrite method, which can get the response message.

@ControllerAdvice
public class CustomResponseBodyAdviceAdapter implements ResponseBodyAdvice<Object> {
    
    

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

    @Override
    public Object beforeBodyWrite(Object body,
                                  MethodParameter methodParameter,
                                  MediaType mediaType,
                                  Class<? extends HttpMessageConverter<?>> aClass,
                                  ServerHttpRequest serverHttpRequest,
                                  ServerHttpResponse serverHttpResponse) {
    
    

        if (serverHttpRequest instanceof ServletServerHttpRequest &&
                serverHttpResponse instanceof ServletServerHttpResponse) {
    
    
            // 打印响应body
        }

        return body;
    }
}

おすすめ

転載: blog.csdn.net/haiyan_qi/article/details/109960325