去年在开放中遇到过一个问题,因为项目重构,数据库等完全的重构,所以线上产生了两套环境。由于我们做的是开放平台,已经有很多开发者对接了,所以老的服务需要保留,一时间需要维护两套服务,老服务中很多应用遇到问题,无法修改应用信息,需要联系客服然后我们手动修改,非常麻烦。于是项目组决定将老的数据订正到新的表中,然后在老的服务中做一次向上的转发,如果失败了再走老的平台。所以需要重复读取HTTP请求的body数据,团队leader给了思路,写一个request的包装类,将读到的inputstream缓存到内存中,便可以重复读取。先上代码:
import org.apache.commons.io.IOUtils;
import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.ByteArrayInputStream;
import java.io.IOException;
/**
* HttpServletRequestWrapper的包装类,用于重复读取inputStream
*
* Created by yuanjian on 10/17/17
* @author liuyj@shinemo.com
*/
public class InputStreamReadRepeatableRequestWrapper extends HttpServletRequestWrapper {
private ServletInputStream inputStream;
public InputStreamReadRepeatableRequestWrapper(HttpServletRequest request) {
super(request);
}
@Override
public ServletInputStream getInputStream() throws IOException {
if (this.getContentLength() < 1) {
return null;
}
if (this.inputStream == null) {
this.inputStream = new InputStreamReadRepeatableRequestWrapper.ReadRepeatableInputStream(this.getRequest().getInputStream(), this.getRequest().getContentLength());
}
return inputStream;
}
private class ReadRepeatableInputStream extends ServletInputStream {
private final ByteArrayInputStream bi;
private ReadRepeatableInputStream(ServletInputStream inputStream, int length) throws IOException {
if (length > 0) {
byte[] bytes = new byte[length];
IOUtils.read(inputStream, bytes, 0, length);
inputStream.read(bytes, 0, length);
bi = new ByteArrayInputStream(bytes, 0, length);
} else {
bi = null;
}
}
@Override
public int read() throws IOException {
int bt = -1;
if (bi != null) {
bt = this.bi.read();
if (bt == -1) {
this.bi.reset();
}
}
return bt;
}
@Override
public void reset() {
this.bi.reset();
}
@Override
public boolean isFinished() {
return false;
}
@Override
public boolean isReady() {
return false;
}
@Override
public void setReadListener(ReadListener readListener) {
}
}
}
然后新增一个filter
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
/**
* @author liuyj@shinemo.com
*/
public final class RequestFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
InputStreamReadRepeatableRequestWrapper request = new InputStreamReadRepeatableRequestWrapper((HttpServletRequest) servletRequest);
filterChain.doFilter(request, servletResponse);
}
@Override
public void destroy() {
}
}
最后只需要在web.xml中配置此filter即可。