java打印http接口的请求和响应

打印http接口的请求和响应

一、简述

基于spring提供的机制,有3种方法可以实现接口请求响应日志的打印,分别是CommonsRequestLoggingFilter、HandlerInterceptor、RequestBodyAdviceAdapter、ResponseBodyAdvice。

二、修改日志级别打印请求参数

通过设置 web 的日志级别为 DEBUG,spring会自己打印请求参数。该方法打印的内容覆盖了后面介绍的所有方法中日志的内容,如果不需要做定制打印,并且不介意打印的日志级别是DEBUG,那就足够用了。

logging:
  level:
    root: INFO
    web: DEBUG

三、使用 CommonsRequestLoggingFilter 打印请求参数

CommonsRequestLoggingFilter的使用比较简单,只需要实现一个logFilter的bean即可。
只不过logFilter的日志级别是debug,需要在日志配置文件中,将CommonsRequestLoggingFilter类的日志级别设置为debug级别。
同时在生产环境的日志文件中打印debug日志不符合规范。

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

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

    return loggingFilter;
}

四、使用 HandlerInterceptor 打印请求参数

HandlerInterceptor 可以获取到接口执行过程中的 HttpServletRequest 和 HttpServletResponse 信息,因此能够打印出接口请求响应内容。

@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;
    }
}

这种方式有个缺陷,对于 application/json 这种请求参数放在body中的方式,需要通过InputStream读取内容,而InputStream只能被读取一次,
一旦在 HandlerInterceptor 中进行了 InputStream 的读取操作,后续的处理就读取不到InputStream中的内容,这是一个很严重的问题。
因此 HandlerInterceptor 不能用于打印请求中的body,可以改造一下该方法,只打印get请求参数,post的请求参数用下面介绍的 RequestBodyAdviceAdapter 方法打印。

@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;
    }
}

五、使用 RequestBodyAdviceAdapter 打印请求参数

RequestBodyAdviceAdapter 封装了 afterBodyRead 方法,在这个方法中可以通过 Object body 参数获取到body的内容。

@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);
    }
}

六、使用 ResponseBodyAdvice 打印响应内容

ResponseBodyAdvice 和 RequestBodyAdviceAdapter 同属于 ControllerAdvice。ResponseBodyAdvice 封装了 beforeBodyWrite 方法,可以获取到响应报文。

@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;
    }
}

七、使用 filter 打印请求和响应

通过继承spring的 OncePerRequestFilter实现自定义filter。在filter中读取请求和响应的body需要做一下特殊处理,因为流只能被读取一次,在filter中被读取了,后续的处理就无法再次读取流的内容了。

spring提供了 ContentCachingRequestWrapper和 ContentCachingResponseWrapper两个类来解决这个问题。

@Slf4j
@Component
public class AccessLogFilter extends OncePerRequestFilter {

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
            throws ServletException, IOException {

        ContentCachingRequestWrapper req = new ContentCachingRequestWrapper(request);
        ContentCachingResponseWrapper resp = new ContentCachingResponseWrapper(response);

        try {
            // Execution request chain
            filterChain.doFilter(req, resp);
            // Get body
            byte[] requestBody = req.getContentAsByteArray();
            byte[] responseBody = resp.getContentAsByteArray();
        
            log.info("request body = {}", new String(requestBody, StandardCharsets.UTF_8));
            log.info("response body = {}", new String(responseBody, StandardCharsets.UTF_8));
        } finally {
        // Finally remember to respond to the client with the cached data.
            resp.copyBodyToResponse();
        }    
    }
}

原文链接:https://blog.csdn.net/haiyan_qi/article/details/109960325

  • 26
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
如果您是在使用 Java 进行开发,可以使用 Servlet API 中的 HttpServletRequest 对象来获取请求行信息,并使用 System.out.println() 函数将其打印出来。示例代码如下: ```java import java.io.IOException; import java.io.PrintWriter; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class MyServlet extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String method = request.getMethod(); // 获取请求方法 String url = request.getRequestURL().toString(); // 获取请求 URL String path = request.getRequestURI(); // 获取请求路径 String queryString = request.getQueryString(); // 获取 URL 参数 // 将请求行信息打印到控制台 System.out.println("Method: " + method); System.out.println("URL: " + url); System.out.println("Path: " + path); System.out.println("Query String: " + queryString); // 返回响应给客户端 response.setContentType("text/html;charset=utf-8"); PrintWriter out = response.getWriter(); out.println("<html><body>"); out.println("<h1>Hello World!</h1>"); out.println("</body></html>"); } } ``` 上述代码中,我们定义了一个 Servlet 类,并重写了其 doGet() 方法来处理 GET 请求。在该方法中,我们通过 HttpServletRequest 对象获取了请求行信息,并使用 System.out.println() 函数将其打印出来。当我们访问该 Servlet 时,服务器会输出请求行信息,并返回一个简单的 HTML 页面作为响应

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值