不知道大家有沒有對用戶輸入的東西進行過敏感校驗,若是不進行校驗,用戶屬於一些攻擊腳本,那麼咱們的服務就掛逼啦!因此咱們首先須要經過過濾器將用戶的數據讀出來進行安全校驗,這裏面涉及到一個動做,就是須要將用戶的數據在過濾器中讀出來,進行校驗,經過以後再放行。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