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

web.xml配置文件

  

<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>  

解决 request.getInputStream() 只能获取一次body的问题的更多相关文章

  1. Servlet的Request.getInputStream()只能读取一次问题

    Servlet的Request.getInputStream()只能读取一次问题 这个星期公司的项目接口进行改造,公司的接口有的采用了WebService的方式,有的使用的是Http协议+Servle ...

  2. request.getInputStream() 流只能读取一次问题

    问题: 一次开发过程中同事在 sptring interceptor 中获取 request body 中值,以对数据的校验和预处理等操作 .导致之后spring 在读取request body 值做 ...

  3. 图片上传利用request.getInputStream()获取文件流时遇到的问题

    图片上传功能是我们web里面经常用到的,获得的方式也有很多种,这里我用的是request.getInputStream()获取文件流的方式.想要获取文件流有两种方式,附上代码 int length = ...

  4. Request.getInputStrema只能读取一次的分析过程

    1. 我们先来看一下继承关系HttpServletRequest 接口继承ServletRequest接口 public abstract interface  ServletRequest{ pub ...

  5. 解决SpringMVC拦截器中Request数据只能读取一次的问题

    解决SpringMVC拦截器中Request数据只能读取一次的问题 开发项目中,经常会直接在request中取数据,如Json数据,也经常用到@RequestBody注解,也可以直接通过request ...

  6. 获取【请求体】数据的3种方式(精)(文末代码) request.getInputStream() request.getInputStream() request.getReader()

    application/x- www-form-urlencoded是Post请求默认的请求体内容类型,也是form表单默认的类型.Servlet API规范中对该类型的请求内容提供了request. ...

  7. 拦截器中,request中getReader()和getInputStream()只能调用一次,构建可重复读取inputStream的request.

    由于 request中getReader()和getInputStream()只能调用一次 在项目中,可能会出现需要针对接口参数进行校验等问题. 因此,针对这问题,给出一下解决方案 实现方法:先将Re ...

  8. Springboot框架中request.getInputStream()获取不到上传的文件流

    Springboot框架中用下面的代码,使用request.getInputStream()获取不到上传的文件流 @PostMapping("/upload_img") publi ...

  9. 自定义HttpReqeust,解决request请求参数只能拿一次就失效的问题

    定义一个过滤器并实现如下方法 @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResp ...

随机推荐

  1. JSON——JavaScript 中的使用

    由于JSON非常简单,很快就风靡Web世界,并且成为ECMA标准.几乎所有编程语言都有解析JSON的库,而在JavaScript中,我们可以直接使用JSON,因为JavaScript内置了JSON的解 ...

  2. linux 单机跨进程通信

    一般来说通过网络通信(比如tcp,udp)或者共享内存的方式肯定可以实现跨进程通信,但现在这里要说的是比较偏但实用的几个方法:利用unix域通信(普通网络连接),利用unix域通信(socketpai ...

  3. 【精】iOS GCD 具体解释

    一.介绍 1.什么是GCD? Grand Central Dispatch.是苹果公司开发的一套多核编程的底层API. GCD首次公布在Mac OS X 10.6,iOS4及以上也可用.GCD存在于l ...

  4. PHP经常使用正則表達式汇总

    1.    平时做站点常常要用正則表達式,以下是一些解说和样例,仅供大家參考和改动使用:  2.    "^\d+$" //非负整数(正整数 + 0)  3.    "^ ...

  5. stm32时钟设置函数

    这里涉及到一个很重要的寄存器,时钟配置寄存器:RCC_CFGR #if defined (STM32F10X_LD_VL) || (defined STM32F10X_MD_VL) || (defin ...

  6. Linux Chrome Tab 标题 乱码

    1. 刚装完ubuntu 14.04 英文版, 又装了google chrome 浏览器. 2. 打开chrome浏览器,发现tab也没的标题是乱码: 3. 而系统自带的firefox却没有这个问题, ...

  7. Spring 新手教程(二) 生命周期和作用域

    以下的知识点是针对使用配置文件讲的(annotation相应标签后面文章会具体阐述) Bean的生命周期: 为什么关心这个问题? 我们使用IOC的目的就是为了让Spring IOC帮我们管理对象.从而 ...

  8. C#实现插件的“动态替换”

    如果某个"功能"需要动态更新?这种动态更新,可能是需求驱动的,也可能是为了修改 BUG,面对这种场景,如何实现“热插拔”呢?先解释一下“热插拔”:在系统运行过程动态替换某些功能,不 ...

  9. cef

    http://blog.csdn.net/hats8888/article/details/53886591 http://blog.csdn.net/gong_hui2000/article/det ...

  10. iOS 学习笔记三【segmentedControl分段控制器详细使用方法】

    在iOS开发过程中,分段控制器的使用频率还是蛮高的,下面是我写的一个简单的demo,大家可以把代码直接复制过去,就可以使用,ios9最新支持. // // ViewController.m // 03 ...