`
ayaoxinchao
  • 浏览: 80853 次
  • 性别: Icon_minigender_1
  • 来自: 合肥
社区版块
存档分类
最新评论

request.getInputStream()只能获取一次的问题

阅读更多
问题:在使用HTTP协议实现应用间接口通信时,服务端读取客户端请求过来的数据,会用到request.getInputStream(),第一次读取的时候可以读取到数据,但是接下来的读取操作都读取不到数据
 
原因
1. 一个InputStream对象在被读取完成后,将无法被再次读取,始终返回-1;
2. InputStream并没有实现reset方法(可以重置首次读取的位置),无法实现重置操作;
 
解决方法(缓存读取到的数据)
1.使用requestsession等来缓存读取到的数据,这种方式很容易实现,只要setAttribute和getAttribute就行;
2.使用HttpServletRequestWrapper来包装HttpServletRequest,在MAPIHttpServletRequestWrapper中初始化读取request的InputStream数据,以byte[]形式缓存在其中,然后在Filter中将request转换为包装过的request;代码如下:
 
public class MAPIHttpServletRequestWrapper extends HttpServletRequestWrapper {
	
	private final byte[] body; // 报文

	public MAPIHttpServletRequestWrapper(HttpServletRequest request) throws IOException {
		super(request);
		body = StreamUtil.readBytes(request.getInputStream());
	}
	
	@Override
	public BufferedReader getReader() throws IOException {
		return new BufferedReader(new InputStreamReader(getInputStream()));
	}
	
	@Override
	public ServletInputStream getInputStream() throws IOException {
		final ByteArrayInputStream bais = new ByteArrayInputStream(body);
		return new ServletInputStream() {
			
			@Override
			public int read() throws IOException {
				return bais.read();
			}
		};
	}

}
/**
 * @author Perlin.Yao
 * @date 2014年8月22日
 * @version 1.0
 */
public class HttpServletRequestReplacedFilter implements Filter {

	@Override
	public void destroy() {
		
	}

	@Override
	public void doFilter(ServletRequest request, ServletResponse response,
			FilterChain chain) throws IOException, ServletException {
		ServletRequest requestWrapper = null;  
        if(request instanceof HttpServletRequest) {  
            requestWrapper = new MAPIHttpServletRequestWrapper((HttpServletRequest) request);  
        }  
        if(requestWrapper == null) {  
            chain.doFilter(request, response);  
        } else {  
            chain.doFilter(requestWrapper, response);  
        }  
	}

	@Override
	public void init(FilterConfig arg0) throws ServletException {
		
	}

}
  
<filter>
	<filter-name>requestFilter</filter-name>
	<filter-class>com.ulinkpay.mapi.common.web.HttpServletRequestReplacedFilter</filter-class>
</filter>
	
<filter-mapping>
	<filter-name>requestFilter</filter-name>
	<url-pattern>*.action</url-pattern>
</filter-mapping>
 
 
分享到:
评论
3 楼 love 2017-01-05  
public static <T> T getNativeRequest(ServletRequest request, Class<T> requiredType) {
if (requiredType != null) {
if (requiredType.isInstance(request)) {
return (T) request;
}
else if (request instanceof ServletRequestWrapper) {
return getNativeRequest(((ServletRequestWrapper) request).getRequest(), requiredType);
}
}
return null;
}
2 楼 love 2017-01-05  
好像SpringMVC中,spring会强制获取原始的request,从中获取inputStream。这样似乎就把楼主的方法给破了?
public static <T> T getNativeRequest(ServletRequest request, Class<T> requiredType) {
if (requiredType != null) {
if (requiredType.isInstance(request)) {
return (T) request;
}
else if (request instanceof ServletRequestWrapper) {
return getNativeRequest(((ServletRequestWrapper) request).getRequest(), requiredType);
}
}
return null;
}


1 楼 bingham 2016-02-29  
你好,这种方式确实可以读多次,但我在测试的时候,发现如果参数以POST方式提交,则在被这个过滤器处理后,无法获取到参数值,请问这个有相应的解决方案吗?

相关推荐

    浅谈request.getinputstream只能读取一次的问题

    然而,一个重要的概念是,`getInputStream()`返回的`ServletInputStream`只能被读取一次,这是由其内部实现机制决定的。 首先,我们需要了解Java的`InputStream`类。`InputStream`是所有字节输入流的基类,它定义了...

    springboot 解决InputStream只能读取一次的问题

    本篇文章将详细讲解如何在Spring Boot应用中解决`InputStream`只能读取一次的问题。 首先,了解`InputStream`的工作原理。`InputStream`是Java I/O中的基础类,它定义了读取字节流的基本操作。当我们尝试从`...

    完美解决request请求流只能读取一次的问题

    解决request请求流只能读取一次的问题,我们可以使用自定义的HttpServletRequestWrapper,覆写getInputStream()和getReader()方法,从而实现流的重复读取。这可以在SpringBoot项目中使用Filter拦截器对所有请求流中...

    java 获取request中的请求参数代码详解

    需要注意的是,使用 `getInputStream()` 方法获取 Request Body 中的数据只能使用一次,如果多次调用将会导致流的数据无法到达 Controller 层,报 400 错误。 Java 提供了多种方式来获取 Request 中的请求参数,...

    java私塾面试题----线程和JSP及EJB部分2

    - **request**: 一次HTTP请求的范围,可以跨越多个页面。 - **session**: 持续时间最长,用于维护用户的登录状态等。 - **application**: 全局范围,整个Web应用共享。 #### 5. Request对象的主要方法 - **...

    spring应用中多次读取http post方法中的流遇到的问题

    在Spring应用中,处理HTTP POST请求时,我们通常需要从请求体中获取数据。这篇内容主要探讨了在Spring中如何多次读取HTTP POST方法中的...这个解决方案不仅解决了流只能读一次的问题,还保持了代码的灵活性和可扩展性。

    web文件上传原理讲解与代码

    避免多次调用`getInputStream()`或`getParameter()`方法,因为这些方法只能调用一次。 2. **编码问题**:确保前后端的字符集一致,以免出现乱码。 3. **安全性考虑**:对上传文件进行验证和限制,防止恶意攻击。 ...

    超级有影响力霸气的Java面试题大全文档

    当客户机第一次调用一个Stateful Session Bean 时,容器必须立即在服务器中创建一个新的Bean实例,并关联到客户机上,以后此客户机调用Stateful Session Bean 的方法时容器会把调用分派到与此客户机相关联的Bean实例...

    JAVA程序员面试题(1)\JAVA程序员面试题

    - **执行方式**:JSP在第一次被访问时会被转换成Servlet并编译执行,之后则以Servlet的形式运行;而Servlet则是直接由容器加载并执行。 - **开发便利性**:JSP因为可以直接在页面中嵌入HTML和JavaScript等,所以...

    java面试基础面试

    通过设置`&lt;%@page isThreadSafe="false"%&gt;`可以使得Servlet处于单线程模式,这意味着一次只能处理一个请求,提高了安全性但降低了性能。 #### 五、页面间对象传递 **5.1 常见对象传递方式** - **request**: 适用于...

    java读取http请求中的body实例代码

    - 当调用`getReader()`后,就不能再调用`getInputStream()`,反之亦然,因为它们都与请求体相关联,只能使用一次。 - 如果请求体包含非文本数据(如二进制文件),可能需要使用`getInputStream()`来读取,而不是`...

Global site tag (gtag.js) - Google Analytics