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

	}

}
时间: 2024-10-06 20:04:38

request使用getReader()和getInputStream()获取请求参数报400错误的相关文章

Yii2请求,报400错误

出现400错误是yii2.0的csrf防范策略导致 在components里面添加request配置如下: 'request' => [ // !!! insert a secret key in the following (if it is empty) - this is required by cookie validation 'cookieValidationKey' => '83r5HbITBiMfmiYPOZFdL-raVp4O1VV4', 'enableCookieValid

JavaWeb获取请求参数的两种方式

第一种:通过获取缓冲流读取参数 public void registerUser(HttpServletRequest request, HttpServletResponse response)throws  Exception  { //直接获取请求参数,通过缓冲流读取数据  BufferedReader br=request.getReader();  String inputLine = "";  String json = "";      while (

servlet-api api文档获取请求参数

1.假如有个get请求后面带有的参数如下: a=b&a2=b2&a3=b3&a4=b4. 如果想获取所有的key,value.这个时候可以根据request的getQueryString获取.但是这样有个问题,getQueryString方法并不会对参数进行解码. 可以使用: String decode = URLDecoder.decode(url, “utf-8”)方法进行解码操作. 2.假如请求参数是在body中的话,getQueryString方法就不能获取请求参数了. 只

Struts2 -- 获取请求参数

1.直接将action做一个model,就可以得到请求参数. 缺点:需要单独定义javaBean,将action中属性copy到javaBean中.                     优点:简单.                                 这种方式 ,底层是通过反射来实现的. //获取请求参数 属性驱动 第一种,直接将action做为model public class DemoAction extends ActionSupport { private String

学习SpirngMVC之如何获取请求参数

学习SpringMVC——如何获取请求参数 @RequestParam,你一定见过:@PathVariable,你肯定也知道:@QueryParam,你怎么会不晓得?!还有你熟悉的他(@CookieValue)!她(@ModelAndView)!它(@ModelAttribute)!没错,仅注解这块,spring mvc就为你打开了五彩斑斓的世界.来来来,不要兴(mi)奋(hu),坐下来,我们好好聊聊这么些个注解兄弟们~~~(wait, 都没有听过? 好,来,你坐前排,就你!) 一.spring

SpringBoot使用AOP获取请求参数

package com.*.aop; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; import lombok.extern.slf4j.Slf4j; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.Signature; impo

六、django分面、获取请求参数

一.获取请求参数 def index(request): limit = request.GET.get('limit',20) #get请求获取请求参数 page = request.GET.get('page',1) username = request.POST.get('name','nana') #post请求获取请求参数 二.分页的方法 from django.core.paginator import Paginator #实现分页的类 l = list(range(100)) #

php 获取请求参数

$value = $_POST["value"];//取得post中的 $value=$_REQUEST["value"];//取得get或者post中的参数(哪个有就取得哪个) $value=$_GET["value"];//取得get中的参数 php 获取请求参数,布布扣,bubuko.com

获取请求参数js代码

/*获取请求参数 */ (function($) {     $.getUrlParam = function(name) {         var reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)");         var r = window.location.search.substr(1).match(reg);         if (r != null)