栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

HttpServletRequest获取输入流多次读取的问题

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

HttpServletRequest获取输入流多次读取的问题

目录

背景

坑点介绍

解决方法


背景

我们在做接口调用的时候使用POST方法发送数据,我们习惯于把数据包装成json格式。有些情况下,我们会在Filter中读取请求数据进行数据校验,常用的Http请求方式主要有两种,对于GET方式获取参数比较简单;对于POST方法,我们获取Body的中的数据就会有一个非常大的坑。

坑点介绍

看了Spring的底层源码,我们发现对于POST方法,可使用如下方法从Request中获取Body参数:

代码块
Java
 private String getBody(HttpServletRequest request) throws IOException 
 {     
    InputStream in = request.getInputStream();  
    BufferedReader br = new BufferedReader(new InputStreamReader(in,             
    Charset.forName("UTF-8")));   
    StringBuffer sb = new StringBuffer("");   
    String temp;   
    while ((temp = br.readLine()) != null) {  
     sb.append(temp);    
    } 
    if (in != null) {   
        in.close();   
    }    
    if (br != null) {  
     br.close();    
    }    
    return sb.toString();
}  
 

注意,这里有了一次request.getInputStream()调用。 但是在测试时,一直报JSON格式不正确的错误。经调查发现,项目中使用了公司基础组件中的Filter,而该Filter中也解析了body。同时,不出所料,也是通过调用getInputStream()方法获取的。

原来: 一个InputStream对象在被读取完成后,将无法被再次读取,始终返回-1; InputStream并没有实现reset方法(可以重置首次读取的位置),无法实现重置操作; 因此,当自己写的Filter中调用了一次getInputStream()后,后面再调用getInputStream()读取的数据都为空,所以才报JSON格式不正确的错误。

解决方法

使用HttpServletRequestWrapper进行包装缓存数据
所谓缓存数据,其实就是调用ServletRequest的setAttribute(String s, Object o)来存储数据。 获取到body后,直接缓存 String body = getBody(request); request.setAttribute("body", body);

优点:方便缺点:不能控制第三方Filter 其他地方需要使用body时,只需调用getAttribute方法就能获取数据了: request.getAttribute("body");

HttpServletRequestWrapper包装方法:

Java
public class RequestWrapper extends HttpServletRequestWrapper {    
  private final byte[] body;  
  public RequestWrapper(HttpServletRequest request) throws IOException {   
    super(request);      
    body = getBodyStringFromReq(request).getBytes(Charset.forName("UTF-8")); 
  }      
  
  public String getBodyString() {       
    try {     
      return new String(body, "UTF-8");  
    } catch (UnsupportedEncodingException ex) { 
      return new String(body);      
    }   
  }    
  private String getBodyStringFromReq(ServletRequest request) {  
    StringBuilder sb = new StringBuilder();    
    InputStream inputStream = null;    
    BufferedReader reader = null;     
    try {             
      inputStream = request.getInputStream();  
      reader = new BufferedReader(new InputStreamReader(inputStream, Charset.forName("UTF-8")));  
      String line;           
      while ((line = reader.readLine()) != null) {     
        sb.append(line);         
      }       
    } catch (IOException e) {    
      e.printStackTrace();     
    } finally {      
      if (inputStream != null) {  
        try {        
          inputStream.close();        
        } catch (IOException e) {   
          e.printStackTrace();         
        }           
      }     
      if (reader != null) {   
        try {       
          reader.close();   
        } catch (IOException e) {     
          e.printStackTrace();   
        }         
      }     
    }        
    return sb.toString(); 
  } 
}  
​
 

在Filter中使用时,FilterChain.doFilter()传入Wrapper对象:

代码块
Java
public class TestFilter implements Filter { 
  @Override    
  public void destroy() { 
  }     
  @Override  
  public void doFilter(ServletRequest request, ServletResponse response,             FilterChain chain) throws IOException, ServletException { 
    RequestWrapper requestWrapper = new RequestWrapper((HttpServletRequest)request);     
    String body = requestWrapper.getBodyString();    
    chain.doFilter(requestWrapper, response);  
    //传入Wrapper对象 
  }   
    @Override    
    public void init(FilterConfig arg0) throws ServletException {     
    } 
  } 
 

这样,位于后面的Filter就可以拥有唯一一次调用HttpServletRequest.getInputStream()的机会了。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/785794.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号