inputstream重复使用,复制inputstream
目录
构建可重复读取输入流的请求请求中输入流多次读取原因解决方法(缓存读取到的数据)代码
构建可重复读取inputStream的request
我们知道,请求的输入流只能被读取一次,多次读取将报错,那么如何才能重复读取呢?答案之一是:增加缓冲,记录已读取的内容。
代码如下所示:
导入龙目岛。外部人员。log4j。log4j 2;导入组织。spring框架。嘲笑。网络。delegatingservletinputstream导入javax。servlet。servlet inputstream导入javax。servlet。http。http servlet请求;导入javax。servlet。http。http servlet请求包装器;导入Java。io。*;/***请求包装器:可重复读取请求。getinputstream */@ log4j 2 public类RepeatedlyReadRequestWrapper扩展http servlet请求包装器{ private static final int BUFFER _ START _ POSITION=0;私有静态final int CHAR _ BUFFER _ LENGTH=1024;/** *输入流的缓冲*/私有最终字符串体;/* * * * @ param request { @ link javax。servlet。http。http servlet请求}对象/public repeated lyreadrequestwrapper(http servlet请求请求){超级(请求);StringBuilder StringBuilder=new StringBuilder();输入流输入流=空请尝试{ inputStream=请求。getinputstream();} catch (IOException e) { log.error(读取请求正文时出错…’,e);} if (inputStream!=null){ try(buffered reader buffered reader=new buffered reader(new inputStream reader(inputStream))){ CHAR[]CHAR BUFFER=new CHAR[CHAR _ BUFFER _ LENGTH];int bytesReadwhile((读取的字节=缓冲的读取器。read(char BUFFER))0){ stringbuilder。append(char BUFFER,BUFFER_START_POSITION,bytes read);} } catch(io异常e){ log。错误(读取输入流失败,e);} } else { stringbuilder。append();} body=stringbuilder。tostring();} @ Override public ServletInputStream getInputStream()抛出io异常{最终bytearray输入流bytearray输入流=新bytearray输入流(body。getbytes());返回新的DelegatingServletInputStream(bytearrayiputstream);}}接下来,需要一个对应的过滤器。
代码如下所示:
e class="brush:java;">import javax.servlet.*;import javax.servlet.http.HttpServletRequest;import java.io.IOException;public class RepeatlyReadFilter implements Filter { @Override public void init(FilterConfig filterConfig) throws ServletException { //Do nothing } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { if (request instanceof HttpServletRequest) { request = new RepeatedlyReadRequestWrapper((HttpServletRequest) request); } chain.doFilter(request, response); } @Override public void destroy() { //Do nothing }}最后,需要在web.xml中,增加该Filter的配置(略)。
request中inputStream多次读取
在使用HTTP协议实现应用间接口通信时,服务端读取客户端请求过来的数据,会用到request.getInputStream(),第一次读取的时候可以读取到数据,但是接下来的读取操作都读取不到数据。
原因
一个InputStream对象在被读取完成后,将无法被再次读取,始终返回-1;
InputStream并没有实现reset方法(可以重置首次读取的位置),无法实现重置操作;
解决方法(缓存读取到的数据)
使用request、session等来缓存读取到的数据,这种方式很容易实现,只要setAttribute和getAttribute就行;
使用HttpServletRequestWrapper来包装HttpServletRequest,在中初始化读取request的InputStream数据,以byte[]形式缓存在其中,然后在Filter中将request转换为包装过的request;
代码
编写rHttpServletRequestWrapper子类,用来处理请求数据
import java.io.BufferedReader;import java.io.ByteArrayInputStream;import java.io.IOException;import java.io.InputStreamReader;import java.nio.charset.Charset;import java.util.Enumeration;import javax.servlet.ReadListener;import javax.servlet.ServletInputStream;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletRequestWrapper;import lombok.extern.slf4j.Slf4j;@Slf4jpublic class BodyReaderHttpServletRequestWrapper extends HttpServletRequestWrapper{private final byte[] body;public BodyReaderHttpServletRequestWrapper(HttpServletRequest request) throws IOException{super(request);Enumeration<String> e = request.getHeaderNames();while (e.hasMoreElements()){String name = (String) e.nextElement();String value = request.getHeader(name);log.debug("HttpServletRequest头信息:{}-{}", name, value);}body = HttpHelper.getBodyString(request).getBytes(Charset.forName("UTF-8"));}@Overridepublic BufferedReader getReader() throws IOException{return new BufferedReader(new InputStreamReader(getInputStream()));}@Overridepublic ServletInputStream getInputStream() throws IOException{final ByteArrayInputStream bais = new ByteArrayInputStream(body);return new ServletInputStream(){@Overridepublic boolean isFinished(){return false;}@Overridepublic boolean isReady(){return false;}@Overridepublic void setReadListener(ReadListener listener){}@Overridepublic int read() throws IOException{return bais.read();}};}@Overridepublic String getHeader(String name){return super.getHeader(name);}@Overridepublic Enumeration<String> getHeaderNames(){return super.getHeaderNames();}@Overridepublic Enumeration<String> getHeaders(String name){return super.getHeaders(name);}}
调用
public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException, ServletException{HttpServletRequest httpRequest = (HttpServletRequest) request;HttpServletResponse httpResponse = (HttpServletResponse) response;ServletRequest requestWrapper = null;requestWrapper = new BodyReaderHttpServletRequestWrapper(httpRequest);//数据读取处理//...//将requestWrapper专递给后面的过滤器filterChain.doFilter(requestWrapper, httpResponse);}
以上为个人经验,希望能给大家一个参考,也希望大家多多支持盛行IT。
郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。