打印http request body 和 response body 以及請(qǐng)求日志跟蹤

1、request 的inputStream和response 的outputStream默認(rèn)情況下是只能讀一次, 不可重復(fù)讀;
這就導(dǎo)致要獲取請(qǐng)求體或者響應(yīng)體信息時(shí)必須要聲明包裹類(lèi)wrapper; spring為此提供了兩個(gè)對(duì)應(yīng)的包裹類(lèi)
ContentCachingRequestWrapper和ContentCachingResponseWrapper使得這兩個(gè)流信息可重復(fù)讀;

因此可以利用這兩個(gè)類(lèi)讀取請(qǐng)求和響應(yīng)信息,輸出到日志

import lombok.extern.slf4j.Slf4j;
import org.slf4j.MDC;
import org.springframework.core.Ordered;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
import org.springframework.web.util.ContentCachingRequestWrapper;
import org.springframework.web.util.ContentCachingResponseWrapper;
import org.springframework.web.util.WebUtils;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.Enumeration;
import java.util.UUID;

/**
 * @Author: xxx
 * @Description:
 * @Date: created in 13:46 2018/7/7
 */
@Component
@Slf4j
public class WebLogFilter extends OncePerRequestFilter implements Ordered {

    // put filter at the end of all other filters to make sure we are processing after all others
    private int order = Ordered.LOWEST_PRECEDENCE - 8;

    public static final String SPLIT_STRING_M = "=";

    public static final String SPLIT_STRING_DOT = ", ";

    @Override
    public int getOrder() {
        return order;
    }

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        //日志trade
        MDC.clear();
        MDC.put("trade_id", UUID.randomUUID().toString().replaceAll("-",""));
        ContentCachingRequestWrapper wrapperRequest = new ContentCachingRequestWrapper(request);
        ContentCachingResponseWrapper wrapperResponse = new ContentCachingResponseWrapper(response);
        String urlParams = getRequestParams(request);
        filterChain.doFilter(wrapperRequest, wrapperResponse);

        String requestBodyStr = getRequestBody(wrapperRequest);
        log.info("params[{}]|body:{}", urlParams, requestBodyStr);

        String responseBodyStr = getResponseBody(wrapperResponse);

        log.info("resp body:{}", responseBodyStr);
        wrapperResponse.copyBodyToResponse();
    }

    /**
     * 打印請(qǐng)求參數(shù)
     * @param request
     */
    private String getRequestBody(ContentCachingRequestWrapper request) {
        ContentCachingRequestWrapper wrapper = WebUtils.getNativeRequest(request, ContentCachingRequestWrapper.class);
        if(wrapper != null) {
            byte[] buf = wrapper.getContentAsByteArray();
            if(buf.length > 0) {
                String payload;
                try {
                    payload = new String(buf, 0, buf.length, wrapper.getCharacterEncoding());
                } catch (UnsupportedEncodingException e) {
                    payload = "[unknown]";
                }
                return payload.replaceAll("\\n","");
            }
        }
        return "";
    }

    /**
     * 打印請(qǐng)求參數(shù)
     * @param response
     */
    private String getResponseBody(ContentCachingResponseWrapper response) {
        ContentCachingResponseWrapper wrapper = WebUtils.getNativeResponse(response, ContentCachingResponseWrapper.class);
        if(wrapper != null) {
            byte[] buf = wrapper.getContentAsByteArray();
            if(buf.length > 0) {
                String payload;
                try {
                    payload = new String(buf, 0, buf.length, wrapper.getCharacterEncoding());
                } catch (UnsupportedEncodingException e) {
                    payload = "[unknown]";
                }
                return payload;
            }
        }
        return "";
    }

    /**
     * 獲取請(qǐng)求地址上的參數(shù)
     * @param request
     * @return
     */
    public static String getRequestParams(HttpServletRequest request) {
        StringBuilder sb = new StringBuilder();
        Enumeration<String> enu = request.getParameterNames();
        //獲取請(qǐng)求參數(shù)
        while (enu.hasMoreElements()) {
            String name = enu.nextElement();
            sb.append(name + SPLIT_STRING_M).append(request.getParameter(name));
            if(enu.hasMoreElements()) {
                sb.append(SPLIT_STRING_DOT);
            }
        }
        return sb.toString();
    }
}

2、利用slf4j的MDC跟蹤請(qǐng)求信息, 打印完整的請(qǐng)求處理日志;主要代碼如下

        //日志trade
        MDC.clear();
        //給本次請(qǐng)求分配一個(gè)唯一的tradeId
        MDC.put("trade_id", UUID.randomUUID().toString().replaceAll("-",""));

并在日志配置文件里加上trade_id的信息,如下

[%X{trade_id}]%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n

到此完成日志跟蹤功能, 效果如下

[16fbd9304e23492cab3ccabb6a85d0c0]2018-07-07 16:18:49.130  INFO 13712 --- [nio-8188-exec-1] ren.xx.xx.filter.WebLogFilter       : params[ggii=44]|body:{    "account":"xxxxx",  "v_code":"056036"}
[16fbd9304e23492cab3ccabb6a85d0c0]2018-07-07 16:18:49.131  INFO 13712 --- [nio-8188-exec-1] ren.xx.xx.filter.WebLogFilter       : resp body:{"code":1,"msg":"請(qǐng)輸入正確的驗(yàn)證碼","data":"","success":false}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Spring Cloud為開(kāi)發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見(jiàn)模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,694評(píng)論 19 139
  • Spring Web MVC Spring Web MVC 是包含在 Spring 框架中的 Web 框架,建立于...
    Hsinwong閱讀 22,968評(píng)論 1 92
  • 國(guó)家電網(wǎng)公司企業(yè)標(biāo)準(zhǔn)(Q/GDW)- 面向?qū)ο蟮挠秒娦畔?shù)據(jù)交換協(xié)議 - 報(bào)批稿:20170802 前言: 排版 ...
    庭說(shuō)閱讀 12,516評(píng)論 6 13
  • 自己從來(lái)都知道現(xiàn)實(shí)的殘酷,也從來(lái)沒(méi)有向現(xiàn)實(shí)低過(guò)頭,也在一直努力著在與命運(yùn)的斗爭(zhēng)中占據(jù)主動(dòng)。但當(dāng)現(xiàn)實(shí)最大的問(wèn)題真的襲...
    舊子琰閱讀 238評(píng)論 0 0
  • (子夜分別占各詩(shī)依次各聯(lián)聯(lián)首) 子夜 子夜無(wú)眠須進(jìn)酒 吳剛釀桂醉春秋 嫦娥起舞高圓闕 氣朗乾坤曲更悠 [仄起][平...
    不惑而歌閱讀 1,382評(píng)論 10 9

友情鏈接更多精彩內(nèi)容