不知道大家有没有对用户输入的东西进行过敏感校验,若是不进行校验,用户属于一些攻击脚本,那么咱们的服务就挂逼啦!因此咱们首先须要经过过滤器将用户的数据读出来进行安全校验,这里面涉及到一个动做,就是须要将用户的数据在过滤器中读出来,进行校验,经过以后再放行。java
问题
若是咱们的数据是get请求倒还好,可是若是是一些数据量比较大,咱们须要经过post json的方式来讲传递数据的时候,这个时候实际上是经过流的方式传递的,若是在过滤器中将参数读取出来以后,而后放行,等到到Servlet的时候,@RequestBody是没法获取到数据的,由于post json使用流传递,流被读取以后就不存在了,因此咱们在过滤器中读取以后,@ReqeustBody天然就读不到数据了,同时会报以下一个错误。json
- 在过滤器中读取body中的数据
@WebFilter @Slf4j public class CheckUserFilter implements Filter { @Override public void doFilter(ServletRequest req, ServletResponse res, FilterChain filterChain) throws IOException, ServletException { HttpServletRequest request = (HttpServletRequest) req; // 在过滤器中读取数据 BufferedReader reader = request.getReader(); StringBuilder sb = new StringBuilder(); String line; while ((line = reader.readLine()) != null) { sb.append(line); } reader.close(); System.out.println(sb.toString()); filterChain.doFilter(request, res); } }
- 出现异常,就是说内容已经被读取了,你不能调用了
{ "id":"1", "username":"bingfeng"} java.lang.IllegalStateException: UT010003: Cannot call getInputStream(), getReader() already called at io.undertow.servlet.spec.HttpServletRequestImpl.getInputStream(HttpServletRequestImpl.java:666) at javax.servlet.ServletRequestWrapper.getInputStream(ServletRequestWrapper.java:152) at javax.servlet.ServletRequestWrapper.getInputStream(ServletRequestWrapper.java:152)
解决
- HttpServletRequestWrapper
那么出现这种问题怎么办呢?能不能经过一个中间的变量将这些数据保存下来,而后咱们就能够一直读取了,这样不就解决了这个问题了吗?那保存在哪里呢?这个时候 HttpServletRequestWrapper 就排上用场了。数组
这个其实你能够把它理解为Request的包装类,Reqeust中有的方法它都有,咱们经过继承这个类,重写该类中的方法,将body中的参数保存一个byte数组中,而后放行的时候将这个包装类传递进去,不就能够一直拿到参数了?安全
- 封装Request类
public class BodyReaderHttpServletRequestWrapper extends HttpServletRequestWrapper { private final byte[] body; /** * 全部参数的集合 */ private Map<String, String[]> parameterMap; public BodyReaderHttpServletRequestWrapper(HttpServletRequest request) throws IOException { super(request); BufferedReader reader = request.getReader(); body = readBytes(reader); parameterMap = request.getParameterMap(); } @Override public BufferedReader getReader() throws IOException { ServletInputStream inputStream = getInputStream(); if (null == inputStream) { return null; } return new BufferedReader(new InputStreamReader(inputStream)); } @Override public Enumeration<String> getParameterNames() { Vector<String> vector = new Vector<>(parameterMap.keySet()); return vector.elements(); } @Override public ServletInputStream getInputStream() throws IOException { if (body == null) { return null; } final ByteArrayInputStream bais = new ByteArrayInputStream(body); return new ServletInputStream() { @Override public boolean isFinished() { return false; } @Override public boolean isReady() { return false; } @Override public void setReadListener(ReadListener listener) { } @Override public int read() throws IOException { return bais.read(); } }; } /** * 经过BufferedReader和字符编码集转换成byte数组 * * @param br * @return * @throws IOException */ private byte[] readBytes(BufferedReader br) throws IOException { String str; StringBuilder retStr = new StringBuilder(); while ((str = br.readLine()) != null) { retStr.append(str); } if (StringUtils.isNotBlank(retStr.toString())) { return retStr.toString().getBytes(StandardCharsets.UTF_8); } return null; } }
- 将过滤器改造
@WebFilter @Slf4j public class CheckUserFilter implements Filter { @Override public void doFilter(ServletRequest req, ServletResponse res, FilterChain filterChain) throws IOException, ServletException { HttpServletRequest request = (HttpServletRequest) req; BodyReaderHttpServletRequestWrapper requestWrapper = new BodyReaderHttpServletRequestWrapper(request); // 从Request的包装类中读取数据 BufferedReader reader = requestWrapper.getReader(); StringBuilder sb = new StringBuilder(); String line; while ((line = reader.readLine()) != null) { sb.append(line); } reader.close(); System.out.println(sb.toString()); filterChain.doFilter(requestWrapper, res); } }
通过这样的配置以后,咱们即便在过滤器中获取了参数,请求也会到达Servlet。app
若是基础知识IO那块不是很扎实的话,第一眼看到这个问题确实挺懵逼的。我也是百度以后解决的,确实值得记录一下,有时候咱们会对全部请求进来的参数进行保存输出什么的,这个时候若是是post json数据的话,若是不是特别明白,可能也会出现这种问题。ide
<p style="text-align:center;font-weight:bold;color:#0e88eb;font-size:20px">日拱一卒,功不唐捐</p>post
<p style="text-align:center;font-weight:bold;color:#773098;font-size:16px">更多内容请关注</p>ui