你請求我接口,傳了什么參數,我返回了什么值給你,全部記下來。防止扯皮
需求:記錄每次用戶請求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 { RequestLogWrapper requestWapper = null; if (servletRequest instanceof HttpServletRequest) { HttpServletRequest request = (HttpServletRequest) servletRequest; if (!request.getRequestURI().toLowerCase().contains("swagger")
&& !request.getRequestURI().toLowerCase().contains("upload")) { //排除swagger、上傳文件等接口 requestWapper = new RequestLogWrapper(request); } } ResponseLogWrapper responseLogWrapper = new ResponseLogWrapper(servletResponse); //獲取請求中的流如何,將取出來的字符串,再次轉換成流,然后把它放入到新request對象中 // 在chain.doFiler方法中傳遞新的request對象 if (requestWapper == null) { filterChain.doFilter(servletRequest, servletResponse); } else { filterChain.doFilter(requestWapper, responseLogWrapper); } //打印返回響應日志 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(); logger.info("{}{}\r\n{}", request.getRequestURI(), queryStr, 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) { } } }
參考資源:
https://www.jianshu.com/p/ba2d5101ad90
https://blog.csdn.net/qq_38132283/article/details/107685797
