你请求我接口,传了什么参数,我返回了什么值给你,全部记下来。防止扯皮
需求:记录每次用户请求Controller的Body参数,
思路:在每个Controller 该当中记录,容易漏记,如果在拦截器里面记的话,可以统一处理
问题:在postHandle 里面记,request.getInputStream() 取出来是空的,放在preHandle里面,就进不到 Controller 里面了。报:I/O error while reading input message; nested exception is java.io.IOException: Stream closed
原因:在拦截器已经读取了请求体中的内容,这时候请求的流中已经没有了数据,就是说HttpServletRequest
请求体中的内容一旦读取就不不存在了,所以直接读取是不行的。
方案:对httprequest进行修饰,自定义的包装类来实现
添加 RequestLogFilter
import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Component; import javax.servlet.*; import javax.servlet.annotation.WebFilter; import javax.servlet.http.HttpServletRequest; import java.io.IOException; @Component @WebFilter(filterName = "requestLogFilter",urlPatterns = {"/*"}, initParams = {@WebInitParam(name = "ignoredUrl", value = ".css;.js;.jpg;.png;.gif;.ico;.html"), @WebInitParam(name = "filterPath", value = "/user/login#/user/registerUser")}) public class RequestLogFilter implements OncePerRequestFilter { private Logger logger = LoggerFactory.getLogger(this.getClass()); @Override protected void doFilterInternal(HttpServletRequest servletRequest, HttpServletResponse servletResponse, FilterChain filterChain) throws ServletException, IOException { boolean writeLog = true; String ignoreLog = "swagger;upload;.jpg;.png;.zip;.dat;.ico;.pdf;download"; //可以放配置文件 RequestLogWrapper requestWapper = null; if (servletRequest instanceof HttpServletRequest) { HttpServletRequest request = (HttpServletRequest) servletRequest; for (String item : ignoreLog.split(";")) { if ("/".equals(request.getRequestURI()) || request.getRequestURI().toLowerCase().contains(item)) { //有一个包含就不记 writeLog = false; break; } } if (writeLog) { requestWapper = new RequestLogWrapper(request); } } ResponseLogWrapper responseLogWrapper = new ResponseLogWrapper(servletResponse); //获取请求中的流如何,将取出来的字符串,再次转换成流,然后把它放入到新request对象中 // 在chain.doFiler方法中传递新的request对象 if (requestWapper == null) { filterChain.doFilter(servletRequest, servletResponse); } else { if (writeLog) { filterChain.doFilter(requestWapper, responseLogWrapper); } else { filterChain.doFilter(requestWapper, servletResponse); } } if (writeLog) { //打印返回响应日志 String result = new String(responseLogWrapper.getResponseData()); ServletOutputStream outputStream = servletResponse.getOutputStream(); outputStream.write(result.getBytes()); outputStream.flush(); outputStream.close(); String queryStr = StrUtil.isEmpty(servletRequest.getQueryString()) ? "" : "?" + servletRequest.getQueryString(); logger.info("Response => {}{} \r\n{}", servletRequest.getRequestURI(), queryStr, result); } } @Override public void destroy() { logger.info(">>>> RequestLogFilter destroy <<<<"); } }
添加 RequestLogWapper
import cn.hutool.core.util.StrUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.servlet.ReadListener; import javax.servlet.ServletInputStream; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequestWrapper; import java.io.*; import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; public class RequestLogWrapper extends HttpServletRequestWrapper { private Logger logger = LoggerFactory.getLogger(this.getClass()); private String requestBody; public String getRequestBody() { return requestBody; } public RequestLogWrapper(HttpServletRequest request) throws IOException { super(request); requestBody = getBodyString(request); String queryStr = StrUtil.isEmpty(request.getQueryString()) ? "" : "?" + request.getQueryString(); String remoteAddr = request.getRemoteAddr(); Enumeration<String> headerNames = request.getHeaderNames(); String headerStr = ""; while (headerNames.hasMoreElements()) { String headerName = headerNames.nextElement(); String headerValue = request.getHeader(headerName); headerStr += StrUtil.format("{}:{};", headerName, headerValue); } logger.info("Request => {}{} RemoteAddr => {} \r\n Headers => {}\r\n{}", request.getRequestURI(), queryStr, remoteAddr, headerStr, requestBody); } @Override public ServletInputStream getInputStream() throws IOException { ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(requestBody.getBytes(StandardCharsets.UTF_8)); ServletInputStream servletInputStream = new ServletInputStream() { @Override public boolean isFinished() { return false; } @Override public boolean isReady() { return false; } @Override public void setReadListener(ReadListener readListener) { } @Override public int read() throws IOException { return byteArrayInputStream.read(); } }; return servletInputStream; } @Override public BufferedReader getReader() throws IOException { return new BufferedReader(new InputStreamReader(getInputStream())); } public String getBodyString(HttpServletRequest request) { StringBuilder sb = new StringBuilder(); InputStream inputStream = null; BufferedReader reader = null; try { inputStream = request.getInputStream(); reader = new BufferedReader(new InputStreamReader(inputStream, Charset.forName("UTF-8"))); String line = ""; while ((line = reader.readLine()) != null) { sb.append(line); } } catch (IOException e) { e.printStackTrace(); } finally { if (inputStream != null) { try { inputStream.close(); } catch (IOException e) { e.printStackTrace(); } } if (reader != null) { try { reader.close(); } catch (IOException e) { e.printStackTrace(); } } } return sb.toString(); } }
ResponseLogWrapper
import javax.servlet.ServletOutputStream; import javax.servlet.WriteListener; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponseWrapper; import java.io.*; public class ResponseLogWrapper extends HttpServletResponseWrapper { private ByteArrayOutputStream buffer = null;//输出到byte array private ServletOutputStream out = null; private PrintWriter writer = null; public ResponseLogWrapper(HttpServletResponse resp) throws IOException { super(resp); buffer = new ByteArrayOutputStream();// 真正存储数据的流 out = new WapperedOutputStream(buffer); writer = new PrintWriter(new OutputStreamWriter(buffer, this.getCharacterEncoding())); } /** 重载父类获取outputstream的方法 */ @Override public ServletOutputStream getOutputStream() throws IOException { return out; } /** 重载父类获取writer的方法 */ @Override public PrintWriter getWriter() throws UnsupportedEncodingException { return writer; } /** 重载父类获取flushBuffer的方法 */ @Override public void flushBuffer() throws IOException { if (out != null) { out.flush(); } if (writer != null) { writer.flush(); } } @Override public void reset() { buffer.reset(); } /** 将out、writer中的数据强制输出到WapperedResponse的buffer里面,否则取不到数据 */ public byte[] getResponseData() throws IOException { flushBuffer(); return buffer.toByteArray(); } /** 内部类,对ServletOutputStream进行包装 */ private class WapperedOutputStream extends ServletOutputStream { private ByteArrayOutputStream bos = null; public WapperedOutputStream(ByteArrayOutputStream stream) throws IOException { bos = stream; } @Override public void write(int b) throws IOException { bos.write(b); } @Override public void write(byte[] b) throws IOException { bos.write(b, 0, b.length); } @Override public boolean isReady() { return false; } @Override public void setWriteListener(WriteListener listener) { } } }
参考资源: