request使用getReader()和getInputStream()获取请求参数报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 {

	@Override
	public void init(FilterConfig filterConfig) throws ServletException {
		// TODO Auto-generated method stub

	}
	@Override
	public 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()));
	    }

	}

	@Override
	public void destroy() {
		// TODO Auto-generated method stub

	}
	
	

}

你可能感兴趣的:(java,报400错误,Filter修改参数)