標籤:java filter修改參數 報400錯誤
參考:http://liwx2000.iteye.com/blog/1542431 和http://stackoverflow.com/questions/7318632/java-lang-illegalstateexception-getreader-has-already-been-called-for-this-re
原因:ServletRequest中getReader()和getInputStream()只能調用一次的解決辦法
最近使用spring mvc做項目,資料格式是json,需要對請求參數中的密碼解密,而請求的參數是整個RequestBody,Controller裡是用過@RequestBody擷取的。實現方法是通過一個Filter讀取整個RequestBody並記錄。但是這時就遇到一個問題,ServletRequest的getReader()和getInputStream()兩個方法只能被調用一次,而且不能兩個都調用。那麼如果Filter中調用了一次,在Controller裡面就不能再調用了
解決辦法:
兩個方法都註明方法只能被調用一次,由於RequestBody是流的形式讀取,那麼流讀了一次就沒有了,所以只能被調用一次。既然是因為流只能讀一次的原因,那麼只要將流的內容儲存下來,就可以實現反覆讀取了。
實現方法:先將RequestBody儲存為一個byte數組,然後通過Servlet內建的HttpServletRequestWrapper類覆蓋getReader()和getInputStream()方法,使流從儲存的byte數組讀取。然後再Filter中將ServletRequest替換為ServletRequestWrapper。代碼如下:
public class DecodeFilter implements Filter {@Overridepublic void init(FilterConfig filterConfig) throws ServletException {// TODO Auto-generated method stub}@Overridepublic void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)throws IOException, ServletException {ServletRequest requestWrapper = null; if(request instanceof HttpServletRequest) { requestWrapper = new MyHttpServletRequest((HttpServletRequest) request); } if(null == requestWrapper) { chain.doFilter(request, response); } else { chain.doFilter(requestWrapper, response); } }/** * getInputStream()和getReader() 都只能讀取一次,由於RequestBody是流的形式讀取,那麼流讀了一次就沒有了,所以只能被調用一次。 * 先將RequestBody儲存,然後通過Servlet內建的HttpServletRequestWrapper類覆蓋getReader()和getInputStream()方法, * 使流從儲存的body讀取。然後再Filter中將ServletRequest替換為ServletRequestWrapper * @description * @author yuhy * @date 2015年12月9日 */private class MyHttpServletRequest extends HttpServletRequestWrapper {private String _body; private HttpServletRequest _request; public MyHttpServletRequest(HttpServletRequest request) throws IOException { super(request); _request = request; StringBuffer jsonStr = new StringBuffer(); try (BufferedReader bufferedReader = request.getReader()) { String line; while ((line = bufferedReader.readLine()) != null) jsonStr.append(line); } //擷取到提交測json,將密碼解密後重新複製給requestBody JSONObject json = JSONObject.parseObject(jsonStr.toString()); json.put("trdPwd", DesUtil.decrypt(json.getString("trdPwd"),DesUtil.key)); _body = json.toJSONString(); } @Override public ServletInputStream getInputStream() throws IOException { final ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(_body.getBytes()); return new ServletInputStream() { public int read() throws IOException { return byteArrayInputStream.read(); } }; } @Override public BufferedReader getReader() throws IOException { return new BufferedReader(new InputStreamReader(this.getInputStream())); }}@Overridepublic void destroy() {// TODO Auto-generated method stub}}
request使用getReader()和getInputStream()擷取請求參數報400錯誤