背景知识
项目组需要打印所有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()[] |
调用时许(待完善):
编码实现
- 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 版权协议,转载请附上原文出处链接和本声明。