首頁>技術>

在業務場景中遇到了需要重用inputStream的情況。伺服器端接收到來自客戶端的request後,從request.getInputStream()獲取的servletInputStream中讀取型別引數,對特定型別,需要將該servletInputStream作為request引數轉發到其它服務程式繼續處理。由於讀取型別引數時,servletInputStream已經被讀取過,其pos已經指向servletInputStream中間的某個位置,當我們需要轉發時,無法獲取到原始的servletInputStream。

// mark方法標記了流的當前位置;// 之後透過reset()方法可以將讀取位置重新定位到標記位置。// readlimit 引數表示此輸入流已經讀取readlimit位元組後,標記位置失效,也就不能reset了。public synchronized void mark(int readlimit) {}public synchronized void reset() throws IOException {        throw new IOException("mark/reset not supported");    }// markSupported表示當前流是否支援標記流;InputStream預設不支援。public boolean markSupported() {        return false;    }

從原始碼可知,ServletInputStream並沒有重寫以上三個方法,也就是其不支援標記流,也就不能重置該流。

快取inputStream

不允許對ServletInputStream的多次讀取,那就把它快取起來;這裡透過HttpServletRequestWrapper儲存流的副本。

public class MyHttpServletRequestWrapper extends HttpServletRequestWrapper {    private byte[] body;    public MyHttpServletRequestWrapper(HttpServletRequest request) {        super(request);        try {            body = IOUtils.toByteArray(request.getInputStream());        } catch (IOException ex) {            body = new byte[0];        }    }    @Override    public ServletInputStream getInputStream() throws IOException {        return new ServletInputStream() {            ByteArrayInputStream bais = new ByteArrayInputStream(body);            @Override            public int read() throws IOException {                return bais.read();            }        };    }}
總結

遇到複用inputStream的情況,首先檢視其原始碼,是否支援mark(markSupported());

如果支援mark,就採用mark和reset方式來複用inputStream;但該方法需要指定一個readlimit值,需要根據業務妥善設定該值,否則會出問題。

對於不支援mark的流,需要將流快取起來;快取必然佔用記憶體,只在必要的時候快取流,並且在用完之後妥善關閉。

你愛的科技內容都在這裡。

33
  • BSA-TRITC(10mg/ml) TRITC-BSA 牛血清白蛋白改性標記羅丹明
  • 基於 KubeEdge 和Kuiper的邊緣流式資料處理實踐