实际开发碰到的问题:
springboot项目中,为了防止sql注入,采用Filter拦截器对所有请求流中的json数据进行校验,请求数据没问题则继续向下执行,在后边的代码中应用到请求参数值时,发现request中的json数据为空;除上边描述的情况,尝试过两次从request中获取json数据,第二次同样是获取不到的。
解决request请求流中的数据二次或多次使用问题:
继承HttpServletRequestWrapper,将请求体中的流copy一份,覆写getInputStream()和getReader()方法供外部使用。每次调用覆写后的getInputStream()方法都是从复制出来的二进制数组中进行获取,这个二进制数组在对象存在期间一直存在,这样就实现了流的重复读取。
//增强类
public class BodyReaderHttpServletRequestWrapper extends HttpServletRequestWrapper {
//保存流
private byte[] requestBody = null;
public BodyReaderHttpServletRequestWrapper(HttpServletRequest request) throws IOException {
super(request);
requestBody = StreamUtils.copyToByteArray(request.getInputStream());
}
@Override
public ServletInputStream getInputStream() throws IOException {
final ByteArrayInputStream bais = new ByteArrayInputStream(requestBody);
return new ServletInputStream() {
@Override
public int read() throws IOException {
return bais.read();
}
@Override
public boolean isFinished() {
return false;
}
@Override
public boolean isReady() {
return false;
}
@Override
public void setReadListener(ReadListener readListener) {
}
};
}
@Override
public BufferedReader getReader() throws IOException{
return new BufferedReader(new InputStreamReader(getInputStream()));
}
}
//过滤器
@Component
@WebFilter
public class RequestSqlValidFilter implements Filter {
private final Logger logger = LoggerFactory.getLogger(this.getClass());
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
ServletRequest requestWrapper = new BodyReaderHttpServletRequestWrapper((HttpServletRequest)request);
//请求参数合法,无sql注入
if((sqlValid(request, response))){
chain.doFilter(requestWrapper, response);//requestWrapper中保存着供二次使用的请求数据
}else {
logger.error("RequestSqlValidFilter sqlValid param error");
}
}
@Override
public void destroy() {
}