问题
  在使用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. SDWebImage源代码解析(一)

    一.概念 SDWebImage是一个开源的第三方库,它提供了UIImageView的一个分类.以支持从远程server下载并缓存图片的功能. 二.优势 自从iOS5.0開始.NSURLCache也能够 ...

  2. (二)Redis 笔记——发布&订阅、事务、数据库操作

    1. Redis 发布订阅 1.1 概述 Redis 发布订阅(pub/sub)是一种消息通信模式:发送者(pub)发送消息,订阅者(sub)接收消息. Redis 客户端可以订阅任意数量的频道. 下 ...

  3. Asp.Net WebApi服务端解决跨域方案

    1.特性方式 主要是继承ActionFilterAttribute,重写OnActionExecuted方法,在action执行后,给响应头加上一个键值对. using System.Web.Http ...

  4. Cocos2dx3.0过渡篇 globalZOrder()与localZOrder()

    这篇博客的标题本想叫“...3.0新的渲染...介绍”,最后还是拉不下这个脸.为啥?觉得自己对渲染的认识还是过于表面,谈不上理解.当然了,这并不影响这篇博客继续写下去.下面看一段3.0Release ...

  5. 设置U盘启动

    利用快捷键来设置U盘启动,利用快捷键启动相对来说比较简单快捷,推荐大家使用(重要提醒:选择热键前,请先插入U盘) 组装机主板 品牌笔记本 品牌台式机 主板品牌 启动按键 笔记本品牌 启动按键 台式机品 ...

  6. C# Soap调WebService

    public class WebServiceHelper { /// <summary> /// Soap协议Post方法 /// </summary> /// <pa ...

  7. 算法基础:整数拆分问题(Golang实现)

    一个整数总能够拆分为2的幂的和.比如: 7=1+2+4 7=1+2+2+2 7=1+1+1+4 7=1+1+1+2+2 7=1+1+1+1+1+2 7=1+1+1+1+1+1+1 总共同拥有6种不同的 ...

  8. 复杂可编程逻辑器件CPLD的基本结构

    复杂可编程逻辑器件CPLD的基本结构 文章出处:czhlcai 发布时间: 2008/12/08 | 6911 次阅读 专业薄膜开关打样工厂,12小时加急出货   1.基于乘积项的CPLD结构 CPL ...

  9. gcc -M -MM -MQ -MF -MT -MD

    静态模式规则对一个较大工程的管理非常有用.它可以对整个工程的同一类文件的重建规则进行一次定义,而实现对整个工程中此类文件指定相同的重建规则.比如,可以用来描述整个工程中所有的.o 文件的依赖规则和编译 ...

  10. C#中基本类型占用字节数

    bool -> System.Boolean (布尔型,其值为 true 或者 false) byte -> System.Byte (字节型,占 1 字节,表示 8 位正整数,范围 0 ...