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}