欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

记录一次拦截器post请求参数读取一次的问题

程序员文章站 2022-05-31 11:31:43
...

我的应用场景

给第三方提供数据读取和上送的接口服务,业务要求需要通过接入key和安全key进行接口拦截认证,这样post请求中的参数在拦截器中读取一次会导致其他层(controller)中获取不到参数的问题。

为什么只能读取一遍请求数据流?

那是因为流对应的是数据,数据放在内存中,有的是部分放在内存中。read 一次标记一次当前位置(mark position),第二次read就从标记位置继续读(从内存中copy)数据。 所以这就是为什么读了一次第二次是空了。 怎么让它不为空呢?只要inputstream 中的pos 变成0就可以重写读取当前内存中的数据。javaAPI中有一个方法public void reset() 这个方法就是可以重置pos为起始位置,但是不是所有的IO读取流都可以调用该方法!ServletInputStream是不能调用reset方法,这就导致了只能调用一次getInputStream()。

解决办法

1、目前我在网上看到过重写HttpServletRequestWrapper方法

2、还可以直接在拦截器中如下实现方式

public class MyInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception {
    	if("POST".equalsIgnoreCase(httpServletRequest.getMethod())) {
    		// 获取httpServletRequest中的参数流
	    	StringBuilder stringBuilder = new StringBuilder();
	        BufferedReader bufferedReader = null;
	        InputStream inputStream = null;
	            inputStream = httpServletRequest.getInputStream();
	            if (inputStream != null) {
	                bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
	                char[] charBuffer = new char[128];
	                int bytesRead = -1;
	                while ((bytesRead = bufferedReader.read(charBuffer)) > 0) {
	                    stringBuilder.append(charBuffer, 0, bytesRead);
	                }
	            } else {
	                stringBuilder.append("");
	            }
	    	
	    	// 参数回流向下传递
	        final ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(stringBuilder.toString().getBytes());
	        ServletInputStream servletInputStream = new ServletInputStream() {
	            @Override
	            public boolean isFinished() {
	                return false;
	            }
	            @Override
	            public boolean isReady() {
	                return false;
	            }
	            @Override
	            public void setReadListener(ReadListener readListener) {
	            }
	            @Override
	            public int read() throws IOException {
	                return byteArrayInputStream.read();
	            }
	        };
    	
    	} else {
    		
    	}
		
			return true;   
    }
    @Override
    public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {
    
    
    }

    @Override
    public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {
    }
}

这样也可以将参数向下传递,写的不好之处还望各大佬指教

相关标签: java spring