问题:在使用HTTP协议实现应用间接口通信时,服务端读取客户端请求过来的数据,会用到request.getInputStream(),第一次读取的时候可以读取到数据,但是接下来的读取操作都读取不到数据
原因:
1. 一个InputStream对象在被读取完成后,将无法被再次读取,始终返回-1;
2. InputStream并没有实现reset方法(可以重置首次读取的位置),无法实现重置操作;
解决方法(缓存读取到的数据):
1.使用request、session等来缓存读取到的数据,这种方式很容易实现,只要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>
相关推荐
然而,一个重要的概念是,`getInputStream()`返回的`ServletInputStream`只能被读取一次,这是由其内部实现机制决定的。 首先,我们需要了解Java的`InputStream`类。`InputStream`是所有字节输入流的基类,它定义了...
解决request请求流只能读取一次的问题,我们可以使用自定义的HttpServletRequestWrapper,覆写getInputStream()和getReader()方法,从而实现流的重复读取。这可以在SpringBoot项目中使用Filter拦截器对所有请求流中...
本篇文章将详细讲解如何在Spring Boot应用中解决`InputStream`只能读取一次的问题。 首先,了解`InputStream`的工作原理。`InputStream`是Java I/O中的基础类,它定义了读取字节流的基本操作。当我们尝试从`...
需要注意的是,使用 `getInputStream()` 方法获取 Request Body 中的数据只能使用一次,如果多次调用将会导致流的数据无法到达 Controller 层,报 400 错误。 Java 提供了多种方式来获取 Request 中的请求参数,...
在Spring应用中,处理HTTP POST请求时,我们通常需要从请求体中获取数据。这篇内容主要探讨了在Spring中如何多次读取HTTP POST方法中的...这个解决方案不仅解决了流只能读一次的问题,还保持了代码的灵活性和可扩展性。
避免多次调用`getInputStream()`或`getParameter()`方法,因为这些方法只能调用一次。 2. **编码问题**:确保前后端的字符集一致,以免出现乱码。 3. **安全性考虑**:对上传文件进行验证和限制,防止恶意攻击。 ...
redirect就是服务端根据逻辑,发送一个状态码,告诉浏览器重新去请求那个地址,一般来说浏览器会用刚才请求的所有参数重新请求,所以session,request参数都可以获取。 20、EJB与JAVA BEAN的区别? Java Bean 是可复用...
- 当调用`getReader()`后,就不能再调用`getInputStream()`,反之亦然,因为它们都与请求体相关联,只能使用一次。 - 如果请求体包含非文本数据(如二进制文件),可能需要使用`getInputStream()`来读取,而不是`...
当客户机第一次调用一个Stateful Session Bean 时,容器必须立即在服务器中创建一个新的Bean实例,并关联到客户机上,以后此客户机调用Stateful Session Bean 的方法时容器会把调用分派到与此客户机相关联的Bean实例...
- **执行方式**:JSP在第一次被访问时会被转换成Servlet并编译执行,之后则以Servlet的形式运行;而Servlet则是直接由容器加载并执行。 - **开发便利性**:JSP因为可以直接在页面中嵌入HTML和JavaScript等,所以...
通过设置`<%@page isThreadSafe="false"%>`可以使得Servlet处于单线程模式,这意味着一次只能处理一个请求,提高了安全性但降低了性能。 #### 五、页面间对象传递 **5.1 常见对象传递方式** - **request**: 适用于...