package com.highdatas.mdm.util; import com.alibaba.fastjson.JSON; import lombok.Data; import lombok.extern.slf4j.Slf4j; import org.apache.commons.io.IOUtils; import org.springframework.core.Ordered; import org.springframework.http.HttpStatus; 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.net.URI; import java.net.URISyntaxException; import java.net.URLDecoder; import java.nio.charset.StandardCharsets; import java.time.LocalDateTime; import java.util.Objects; /** * @author kimi * @description * @date 2020-03-17 18:53 */ @Slf4j public class HttpTraceLogFilter extends OncePerRequestFilter implements Ordered { private static final String NEED_TRACE_PATH_PREFIX = "/api"; private static final String IGNORE_CONTENT_TYPE = "multipart/form-data"; @Override public int getOrder() { return Ordered.LOWEST_PRECEDENCE - 10; } @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { if (!isRequestValid(request)) { filterChain.doFilter(request, response); return; } if (!(request instanceof ContentCachingRequestWrapper)) { request = new ContentCachingRequestWrapper(request); } if (!(response instanceof ContentCachingResponseWrapper)) { response = new ContentCachingResponseWrapper(response); } int status = HttpStatus.INTERNAL_SERVER_ERROR.value(); long startTime = System.currentTimeMillis(); try { filterChain.doFilter(request, response); status = response.getStatus(); } finally { String path = request.getRequestURI(); boolean isFilterPath = path.startsWith(NEED_TRACE_PATH_PREFIX); isFilterPath = true; if (isFilterPath) { String requestBody = IOUtils.toString(request.getInputStream(), StandardCharsets.UTF_8.name()); log.info(requestBody); //1. 记录日志 HttpTraceLog traceLog = new HttpTraceLog(); traceLog.setPath(path); traceLog.setMethod(request.getMethod()); long latency = System.currentTimeMillis() - startTime; traceLog.setTimeTaken(latency); traceLog.setTime(LocalDateTime.now().toString()); traceLog.setParameterMap(JSON.toJSONString(request.getParameterMap())); traceLog.setStatus(status); traceLog.setRequestBody(getRequestBody(request)); traceLog.setResponseBody(getResponseBody(response)); log.info("Http trace log: {}", JSON.toJSONString(traceLog)); } updateResponse(response); } } private boolean isRequestValid(HttpServletRequest request) { try { new URI(request.getRequestURL().toString()); return true; } catch (URISyntaxException ex) { return false; } } private String getRequestBody(HttpServletRequest request) { String requestBody = ""; ContentCachingRequestWrapper wrapper = WebUtils.getNativeRequest(request, ContentCachingRequestWrapper.class); if (wrapper != null) { try { requestBody = IOUtils.toString(wrapper.getContentAsByteArray(), wrapper.getCharacterEncoding()); } catch (IOException e) { // NOOP } } return requestBody; } private String getResponseBody(HttpServletResponse response) { String responseBody = ""; ContentCachingResponseWrapper wrapper = WebUtils.getNativeResponse(response, ContentCachingResponseWrapper.class); if (wrapper != null) { try { responseBody = IOUtils.toString(wrapper.getContentAsByteArray(), wrapper.getCharacterEncoding()); } catch (IOException e) { // NOOP } } return responseBody; } private void updateResponse(HttpServletResponse response) throws IOException { ContentCachingResponseWrapper responseWrapper = WebUtils.getNativeResponse(response, ContentCachingResponseWrapper.class); Objects.requireNonNull(responseWrapper).copyBodyToResponse(); } @Data private static class HttpTraceLog { private String path; private String parameterMap; private String method; private Long timeTaken; private String time; private Integer status; private String requestBody; private String responseBody; } }