您好,登錄后才能下訂單哦!
本篇內容介紹了“怎么構建可重復讀取inputStream的request”的有關知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領大家學習一下如何處理這些情況吧!希望大家仔細閱讀,能夠學有所成!
我們知道,request的inputStream只能被讀取一次,多次讀取將報錯,那么如何才能重復讀取呢?答案之一是:增加緩沖,記錄已讀取的內容。
代碼如下所示:
import lombok.extern.log4j.Log4j2; import org.springframework.mock.web.DelegatingServletInputStream; import javax.servlet.ServletInputStream; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequestWrapper; import java.io.*; /** * request wrapper: 可重復讀取request.getInputStream */ @Log4j2 public class RepeatedlyReadRequestWrapper extends HttpServletRequestWrapper { private static final int BUFFER_START_POSITION = 0; private static final int CHAR_BUFFER_LENGTH = 1024; /** * input stream 的buffer */ private final String body; /** * @param request {@link javax.servlet.http.HttpServletRequest} object. */ public RepeatedlyReadRequestWrapper(HttpServletRequest request) { super(request); StringBuilder stringBuilder = new StringBuilder(); InputStream inputStream = null; try { inputStream = request.getInputStream(); } catch (IOException e) { log.error("Error reading the request body…", e); } if (inputStream != null) { try (BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream))) { char[] charBuffer = new char[CHAR_BUFFER_LENGTH]; int bytesRead; while ((bytesRead = bufferedReader.read(charBuffer)) > 0) { stringBuilder.append(charBuffer, BUFFER_START_POSITION, bytesRead); } } catch (IOException e) { log.error("Fail to read input stream",e); } } else { stringBuilder.append(""); } body = stringBuilder.toString(); } @Override public ServletInputStream getInputStream() throws IOException { final ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(body.getBytes()); return new DelegatingServletInputStream(byteArrayInputStream); } }
接下來,需要一個對應的Filter.
代碼如下所示:
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的配置(略)。
在使用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; @Slf4j public 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")); } @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 boolean isFinished() { return false; } @Override public boolean isReady() { return false; } @Override public void setReadListener(ReadListener listener) { } @Override public int read() throws IOException { return bais.read(); } }; } @Override public String getHeader(String name) { return super.getHeader(name); } @Override public Enumeration<String> getHeaderNames() { return super.getHeaderNames(); } @Override public 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); }
“怎么構建可重復讀取inputStream的request”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業相關的知識可以關注億速云網站,小編將為大家輸出更多高質量的實用文章!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。