通过过滤器Filter实现请求响应报文的日志输出

  • Post author:
  • Post category:其他




背景知识

项目组需要打印所有Restful接口的请求及响应报文,而通过HttpServletRequest获取输入流InputStream最多只能获取一次,重复获取会抛异常——Required Request Body is Missing。

相关技术知识点:

接口/类 描述 主要方法
javax.servlet.Filter接口 获取请求Bytes报文;组装RequestWrapper、ResponseWrapper;获取响应Bytes报文;回写Response; public void doFilter(ServletRequest servletRequest,ServletResponse servletResponse,FilterChain filterChain) throws IOException, ServletException
javax.servlet.ServletInputStream接口 自定义InputStream,通过ByteArrayInputStream为后续逻辑提供read()方法,可以形象化理解为请求体的Getter方法; public int read() throws IOException
javax.servlet.ServletOutputStream接口 自定义OutputStream,通过ByteArrayOutputStream为前置逻辑提供write方法,可以形象化理解为响应体的Setter方法; public void write(int b) throws IOException
javax.servlet.http.HttpServletRequestWrapper接口 自定义ServletRequest,获取自定义InputStream public ServletInputStream getInputStream() throws IOException
javax.servlet.http.HttpServletResponseWrapper接口 自定义ServletResponse,获取自定义OutputStream public ServletOutputStream getOutputStream() throws IOException
java.io.ByteArrayInputStream 已byte[]为参构造InputStream public ByteArrayInputStream(byte buf[])
java.io.ByteArrayOutputStream 从OutputStream中获取byte[] public synchronized byte toByteArray()[]

调用时许(待完善):

Filter ServletWrapper ServletStream ByteArrayStream ServletRequestWrapper.getInputStream ServletInputStream.read ByteArrayInputStream(byte buf[]) ByteArrayStream之Input、Output ServletOutputStream.write ServletResponseWrapper.getOutputStream ByteArrayOutputStream.toByteArray Filter ServletWrapper ServletStream ByteArrayStream 请求、响应报文体打印输出



编码实现

  • BodyLogInputStream.java
public class BodyLogInputStream extends ServletInputStream {
	private final ByteArrayInputStream is;
	public BodyLogInputStream(byte[] body) {
		is = new ByteArrayInputStream(body);
	}
	@Override
	public boolean isFinished() {
		return true;
	}
	@Override
	public boolean isReady() {
		return true;
	}
	@Override
	public void setReadListener(ReadListener readListener){
		
	}
	@Override
	public int read() throws IOException {
		return is.read();
	}
}
  • BodyLogOutputStream.java
public class BodyLogOutputStream extends ServletOutputStream {
	private final ByteArrayOutputStream os;
	public BodyLogOutputStream(ByteArrayOutputStream os){
		this.os = os;
	}
	@Override
	public boolean isReady() { return true; }
	@Override
	public void setWriteListener(WriteListener writeListener){ }
	@Override
	public void write(int b) throws IOException {
		os.write(b);
	}
}
  • BodyLogRequestWrapper.java
public class BodyLogRequestWrapper extends HttpServletRequestWrapper {
	private final byte[] body;
	public BodyLogRequestWrapper(HttpServletRequest request, byte[] body){
		super(request);
		this.body = body;
	}
	@Override
	public ServletInputStream getInputStream() throws IOException {
		return new BodyLogInputStream(body);
	}
}
  • BodyLogResponseWrapper.java
public class BodyLogResponseWrapper extends HttpServletResponseWrapper {
	private final ByteArrayOutputStream os;
	public BodyLogResponseWrapper (HttpServletResponse response){
		super(response);
		os = new ByteArrayOutputStream();
	}
	@Override
	public ServletOutputStream getOutputStream() throws IOException {
		return new BodyLogOutputStream(os);
	}
	/**
	* 钩子函数 获取写入OutputStream中的字节数组
	*/
	public byte[] getBytes() throws IOException {
		return BodyLogUtil.getBytes(os);
	}
}
  • BodyLogUtil.java
public class BodyLogUtil {
	public static byte[] getBytes(ByteArrayOutputStream os) throws IOException {
		os.flush();
		byte[] bytes = os.toByteArray();
		os.close();
		return bytes;
	}
	
	public static byte[] getBytes(InputStream is) throws IOException{
		ByteArrayOutputStream os = new ByteArrayOutputStream();
		byte[] buffer = new byte[1024];
		int n = -1;
		while( -1 != (n = is.read(buffer))) {
			os.write(buffer, 0, n);
		}
		is.close();
		return getBytes(os);
	}
	public static void setBytes(OutputStream os,byte[] bytes) throws IOException{
		os.write(bytes);
		os.close();
	}
}
  • BodyLogFilter.java
public class BodyLogFilter implements Filter {
	private final static Logger logger = LoggerFactory.getLogger(BodyLogFilter.class);
	@Override
	public void init(FilterConfig filterConfig) throws ServletException {
		
	}
	@Override
	public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
		//获取请求报文
		byte[] requestData = BodyLogUtil.getBytes(servletRequest.getInputStream());
		logger.info("请求报文:{}",new String(requestData,Charset.forName(servletRequest.getCharacterEncoding())));
	
		//组装RequestWrapper与ResponseWrapper
		BodyLogRequestWrapper requestWrapper = new BodyLogRequestWrapper((HttpServletReuqest)servletRequest, requestData);
		BodyLogResponseWrapper responseWrapper = new BodyLogResponseWrapper((HttpServletResponse)servletResponse);
		filterChain.doFilter(requestWrapper, responseWrapper);
		
		//获取响应报文
		byte[] responseData = responseWrapper.getBytes();
		logger.info("响应报文:{}",new String(responseData,Charset.forName(servletRequest.getCharacterEncoding())));
		
		//回写Reponse
		BodyLogUtil.setBytes(servletResponse.getOutputStream(), responseData);

	}

	@Override
	publiv void destroy() {
		
	}
}



版权声明:本文为Netbug_NB原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。