在用reset接口的時候,常常會使用request.getInputStream()方法,但是流只能讀取一次,一旦想要加上一個過濾器用來檢測用戶請求的數據時就會出現異常。
在過濾器中通過流讀取出用戶post提交過來的數據,這是流已經讀取了一次,那么該流就已經作廢了,所以在contorller再次讀取用戶請求的數據時就會拋出異常。
解決方法
方法一:
參見:http://www.cnblogs.com/jiangxinnju/p/5709378.html
簡單說一下原理,其實就是通過自定義的HttpServletRequestWrapper 備份一下流的數據,自定義HttpServletRequestWrapper 調用父類request.getInputStream()讀取全部數據出來保存在一個byte數組內,當再次獲取流數據的時候,自定義的HttpServletRequestWrapper 就會用byte數組重新生成一個新的流。備份的流數據仍然保留在byte數組中。
方法二:
request.getInputStream()方法只能使用一次,流就會作廢了,其實我們還可以通過另一種方式獲取用戶傳輸的數據,那就是通過
request.getReader()來獲取到一個BufferedReader。這里要說一下BufferedReader是緩存流,並且BufferedReader的markSupported方法是返回true,說明BufferedReader是可以標記和回退的流。
BufferedReader中有defaultCharBufferSize屬性
static { BufferedReader.defaultCharBufferSize = 8192; BufferedReader.defaultExpectedLineLength = 80; }
這里可以看出緩存大小為8192,也就是8KB大小的緩存,所以我們可以用BufferedReader的標記和重置方法來進行重復讀取流。
結語:
方法二的性能會比方法一的性能較快,因為BufferedReader只存在一個實例,而不是每次調用都生成。要注意的是通過BufferedReader的標記和重置方法只能讀取8KB以內的內容。超過8KB進行重復讀取時,將會清空8KB前的緩存,導致標記失效,緩存內容將會丟失。比如:讀取了9KB的內容,那么其中前面的1KB的內容將會在緩存中被清除掉,而只緩存了后面的8KB內容,前面的1KB內容被永久清除了,但后面的8KB內容還是能通過標記重置來進行重復讀取。 (8KB內容相當於4000字)
方法一也是可以做成緩存流的形式,代替每次生成一個新的實例,這里就不一一介紹。
方法一也是有缺點的,就是遇到文件上傳時內存消耗會增加,因為上傳的文件也是在request流中的,一旦上傳較大的文件,服務器將會內存不足導致宕機。
建議最好使用原生自帶的緩存BufferedReader,會更加方便。