2012-02-13 88 views
0

我試圖用javax.servlet.Filter來查看一條消息。如何從過濾器中窺探Mesage?

public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { 
    BufferedReader reader = request.getReader(); 
    if (reader.markSupported()) { 
     reader.mark(contentLen); 
    } 
    String content = reader.readLine(); 

    // search some pattern 

    if (reader.markSupported()) { 
     reader.reset(); 
    } 
    chain.doFilter(request, response); 
} 

終於接收到請求該servlet引發此exeption:

java.lang.IllegalStateException: getReader() has already been called for this request 

其爲根據的Javadoc正確的行爲。

我的問題是我怎樣才能讀取輸入流的內容呢?

我也試過ServletInputStream is = request.getInputStream();

+0

能否克隆請求,然後看看克隆? – 2012-02-13 10:53:21

回答

1

沒有測試,但你很可能

  • 從請求輸入流中讀取所有字節並將其寫入字節數組,
  • 在構建一個緩衝的讀者這個字節數組讀取你想要的過濾器中的數據,
  • 構造一個HttpServletRequestWrapper,它覆蓋getInputStream()返回字節數組上的數據流,
  • 將此包裝傳遞給過濾器鏈。
+0

謝謝,複製似乎是唯一的方法。 – stacker 2012-02-13 12:27:17

+0

這會打開一個簡單的'OutOfMemoryError'漏洞。黑客可能會發送一個大於服務器可用堆的請求主體,從而將服務器完全關閉。查看Apache Commons FileUpload如何處理大文件上傳,方法是將其部分存儲在內存中並保留在臨時磁盤上。或者根據具體的功能要求尋找不同的解決方案。 – BalusC 2012-02-13 12:53:31

+0

@BalusC:有趣。 Tomcat使用設置爲2兆字節的maxPostSize來避免常規請求主體解析出現此問題。我猜OP應該做同樣的事情,並且一旦讀取的字節數超過了X MB,就拋出一個異常。我想知道是否自動將JSON編碼的請求主體轉換爲對象的web框架具有這種最大值,或者它們是否面臨相同的漏洞。 – 2012-02-13 13:10:47

0

ServletRequest.getInputStream()ServletRequest.getReader()是非此即彼的,所以無論是否已經調用,其他人會失敗。您可以使用一個簡單的try-catch來解決此導航:

try { 
    request.getInputStream(); 
} catch (IllegalStateException e) { 
    // someone already called getReader(), so use it instead 
    request.getReader(); 
} 

注意!沒有指定流或閱讀器應該是可重置的,所以如果你消耗掉任何字節,它們將不再可用於鏈中的任何過濾器或servlet。

+0

很難告訴所有這些JSP和其他servlet。不,這不是一個真正可行的「解決方法」,這可能會在某種程度上實現字符編碼時混淆字符編碼。 – BalusC 2012-02-13 13:02:33

1

在從@JB Nizet的形式給出了導致這種代碼:

public class HttpServletRequestCopy extends HttpServletRequestWrapper { 

    private final byte[]  buffer; 

    private ServletInputStream sis; 

    private BufferedReader  reader; 

    public byte[] getBuffer() { 
     return buffer; 
    } 

    public HttpServletRequestCopy(HttpServletRequest request) throws IOException { 
     super(request); 
     final ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); 
     copyStream(request.getInputStream(), byteArrayOutputStream); 
     buffer = byteArrayOutputStream.toByteArray(); 
    } 

    @Override 
    public BufferedReader getReader() throws IOException { 
     if (reader == null) { 
      String characterEncoding = this.getCharacterEncoding(); 
      if (characterEncoding == null) { 
       reader = new BufferedReader(new InputStreamReader(this.getInputStream())); 
      } 
      else { 
       reader = new BufferedReader(new InputStreamReader(this.getInputStream(), characterEncoding)); 
      } 
     } 
     return reader; 
    } 

    @Override 
    public ServletInputStream getInputStream() throws IOException { 
     if (sis == null) { 
      final ByteArrayInputStream bais = new ByteArrayInputStream(buffer); 
      sis = new ServletInputStream() { 
       @Override 
       public int read() throws IOException { 
        return bais.read(); 
       } 
      }; 
     } 
     return sis; 
    } 

    private void copyStream(InputStream input, OutputStream output) throws IOException { 
     final byte[] bytes = new byte[ 1024 ]; 
     int length; 
     while ((length = input.read(bytes)) != -1) { 
      output.write(bytes, 0, length); 
     } 
    } 
}