千家信息网

如何解决为了多次读取ServletInputStream引发的一系列问题

发表于:2026-11-03 作者:千家信息网编辑
千家信息网最后更新 2026年11月03日,本篇内容主要讲解"如何解决为了多次读取ServletInputStream引发的一系列问题",感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习"如何解决为了多次读
千家信息网最后更新 2026年11月03日如何解决为了多次读取ServletInputStream引发的一系列问题

本篇内容主要讲解"如何解决为了多次读取ServletInputStream引发的一系列问题",感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习"如何解决为了多次读取ServletInputStream引发的一系列问题"吧!

目录
  • 多次读取ServletInputStream引发的问题

    • 因为服务器和app之间传输方式是JSON

    • 于是写了下面的filter来让ServletInputStream来多次读取

    • 解决思路:自己解决

  • ServletInputStream重复读取问题

    • 直接贴代码了,亲测能用

多次读取ServletInputStream引发的问题

因为服务器和app之间传输方式是JSON

格式如下

{ head:nullbody:nulltoken:xxxxxxxxxxxxxxxxxxxxx}

所以想在服务端写个拦截器或者filter先读取token,来验证身份.但是如果前置拦截,那么在springMVC里的参数控制器就会读取不到,导致@RequestBody 这个注解的参数不起作用.

原因在于ServletInputStream已经在前置拦截器里读取过一次,在接下来的ArgumentHandler里读取的时候就不能再读了,导致取不到数据而无法赋值.

于是写了下面的filter来让ServletInputStream来多次读取

先写个request

public class MyHttpRequest extends HttpServletRequestWrapper { private static Logger log=Logger.getLogger(MyHttpRequest.class);    private  byte[] bytes;    /**     * @param request {@link javax.servlet.http.HttpServletRequest} object.     * @throws IOException      */    public MyHttpRequest(HttpServletRequest request) throws IOException {        super(request);        bytes= IOUtils.toByteArray( request.getInputStream());          }     @Override    public ServletInputStream getInputStream() throws IOException {        final ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes);        return new DelegatingServletInputStream(byteArrayInputStream);    }    @Override    public BufferedReader getReader() throws IOException {     return new BufferedReader(new InputStreamReader(getInputStream()));    }

以上内容是先读取出来,然后放到一个byte[]里,以后每次拿流的时候就可以再新建一个关于Byte[]的流.

然后再写一个filter

public class MyFilter implements Filter{  @Override public void destroy() {     }  @Override public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)   throws IOException, ServletException {  HttpServletRequest request=(HttpServletRequest) req;  MyHttpRequest myrequest=new MyHttpRequest(request);  chain.doFilter(myrequest, res);   }  @Override public void init(FilterConfig arg0) throws ServletException {   } }

在web.xml里配置一下,试试效果,非常不错.可以多次读取了,

但是,我去

在post请求下,request.getParamter这种东西又不起作用了.

原因在于我们重写的那个request是默认调用父类的super.getparamter方法,而super.getparamter又依赖于super.getInputStream,但是在我们重写的request里的构造方法里,第一句话就老request注入到super里,然后下一句话就把老的request的流给读了,导致我们调用super.getparameter的时候遇到了一个空的流。

解决思路:自己解决

package com.hrhs.jyj.filter; import java.io.BufferedReader;import java.io.ByteArrayInputStream;import java.io.IOException;import java.io.InputStreamReader;import java.io.UnsupportedEncodingException;import java.util.ArrayList;import java.util.Enumeration;import java.util.HashMap;import java.util.List;import java.util.Map; import javax.servlet.ServletInputStream;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletRequestWrapper; import org.apache.commons.io.IOUtils;import org.apache.log4j.Logger;import org.springframework.mock.web.DelegatingServletInputStream; public class MyHttpRequest extends HttpServletRequestWrapper { private static Logger log = Logger.getLogger(MyHttpRequest.class); private byte[] bytes; private String body; private Map> map; private int readMap=0; private String queryString; /**  * @param request  *            {@link javax.servlet.http.HttpServletRequest} object.  * @throws IOException  */ public MyHttpRequest(HttpServletRequest request) throws IOException {  super(request);  bytes = IOUtils.toByteArray(request.getInputStream());  queryString = request.getQueryString();   }  @Override public ServletInputStream getInputStream() throws IOException {  final ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes);  return new DelegatingServletInputStream(byteArrayInputStream); }  @Override public BufferedReader getReader() throws IOException {  return new BufferedReader(new InputStreamReader(getInputStream())); }  @Override public String getParameter(String name) {  log.info("走了getParameter");  return super.getParameter(name); }  @Override public Map getParameterMap() {  log.info("走了getParameterMap");  return super.getParameterMap(); }  @Override public Enumeration getParameterNames() {  log.info("走了getParameterNames");  return super.getParameterNames(); } //暂时先改写这一个,其他的也可以修改 @Override public String[] getParameterValues(String name) {  log.info("走了getParameterValues");  try {   Map> nameVals = doParameter();   List list = nameVals.get(name);   if(list!=null&&list.size()>0){    return list.toArray(new String[]{});   }  } catch (UnsupportedEncodingException e) {   e.printStackTrace();  }  return new String[]{}; } //这里获取所有参数值的map public Map> doParameter() throws UnsupportedEncodingException {  if(readMap==0){   //这里把post里的参数和地址栏参数结合到一起,然后解析   body = new String(bytes, getCharacterEncoding())+"&"+queryString;   String[] nameVals = body.split("&");   map = new HashMap>();   for (String nameVal : nameVals) {    String name = nameVal.split("=")[0];    String val = nameVal.split("=")[1];    if (map.containsKey(name)) {     List vals = map.get(name);     vals.add(val);     map.put(name, vals);    } else {     List vals = new ArrayList();     vals.add(val);     map.put(name, vals);    }   }   readMap=1;  }  return map;   }}

ServletInputStream重复读取问题

本来是想实现tomcat的acess_log打印post请求参数。吐槽一下,tomcat功能和nginx差了好几条街。网上找了个方法,用tomcat的filter来实现。

但是,写filter的时候,发现了ServletInputStream重复读取问题。

网上找个几个方法,都不能直接用。综合网上的资料,根据自己的理解,终于能完美运行了。

直接贴代码了,亲测能用

首先要写个BufferHttpServletRequestWrapper类,用来复制HttpServletRequest request。

import java.io.BufferedReader;import java.io.ByteArrayInputStream;import java.io.ByteArrayOutputStream;import java.io.IOException;import java.io.InputStream;import java.io.InputStreamReader; import javax.servlet.ServletInputStream;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletRequestWrapper; public class BufferHttpServletRequestWrapper extends HttpServletRequestWrapper {  private final byte[] body;  public BufferHttpServletRequestWrapper(HttpServletRequest request) throws IOException {  super(request);  InputStream is = request.getInputStream();        ByteArrayOutputStream baos = new ByteArrayOutputStream();        byte buff[] = new byte[ 1024 ];        int read;        while( ( read = is.read( buff ) ) > 0 ) {            baos.write( buff, 0, read );        }        body = baos.toByteArray(); }  @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();   }  }; } }

然后filter实现如下:

import java.io.ByteArrayOutputStream;import java.io.IOException;import java.io.InputStream;import javax.servlet.Filter;import javax.servlet.FilterChain;import javax.servlet.FilterConfig;import javax.servlet.ServletException;import javax.servlet.ServletRequest;import javax.servlet.ServletResponse;import javax.servlet.http.HttpServletRequest; /** * Servlet Filter implementation class PostDataDumperFilter */ public class PostDataDumperFilter implements Filter {  private FilterConfig filterConfig = null;     /**     * Default constructor.      */    public PostDataDumperFilter() {        // TODO Auto-generated constructor stub    }  /**  * @see Filter#destroy()  */ public void destroy() {  this.filterConfig = null;  }  /**  * @see Filter#doFilter(ServletRequest, ServletResponse, FilterChain)  */ public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {  if (filterConfig == null)    return;  //备份HttpServletRequest  ServletRequest requestWrapper = null;          if(request instanceof HttpServletRequest) {              requestWrapper = new BufferHttpServletRequestWrapper((HttpServletRequest) request);          }  //使用流  InputStream reader = requestWrapper.getInputStream();  ByteArrayOutputStream byteOutput = new ByteArrayOutputStream(100);  int i =0;  byte [] b = new byte[100];  while((i = reader.read(b))!= -1){   byteOutput.write(b, 0, i);  }  request.setAttribute("post", new String(byteOutput.toByteArray()));  // pass the request along the filter chain  if(null == requestWrapper){   chain.doFilter(request, response);  } else {              chain.doFilter(requestWrapper, response);          } }  /**  * @see Filter#init(FilterConfig)  */ public void init(FilterConfig fConfig) throws ServletException {  this.filterConfig = fConfig; } }

到此,相信大家对"如何解决为了多次读取ServletInputStream引发的一系列问题"有了更深的了解,不妨来实际操作一番吧!这里是网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!

问题 参数 方法 时候 内容 服务 一句话 之间 代码 作用 原因 思路 方式 服务器 面的 拦截器 传输 学习 不错 实用 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 有格互联网科技 蓝思科技飞鸽互联网 重生之互联网科技帝国 科技创新与互联网经济 互联网科技金融公司 紫鲸互联网科技 时间互联网络科技 太原新华互联网科技学校怎么样 中国互联网有什么科技含量 栖莱科技互联网股份有限公司 互联网科技项目计划书材料类 互联网科技产业特征 为客找房互联网科技公司怎么样 21世纪互联网科技成就 宇信科技在杭州互联网排第几 郑州欣桑互联网科技有限公司 萌小萌互联网科技河南有限公司 互联网高科技行业有哪些企业 唐山双旺合互联网科技产业园 互联网科技博主张洲 互联网科技资迅 以房互联网科技 新浪科技互联网 火传媒上海互联网科技 互联网科技咨询 科技大学互联网 恒生互联网科技业指数调整周期 广东猫王互联网科技有限公司电话 银川新华互联网科技学校招聘 株洲百竞科技的互联网营销顾问
0