從form的enctype屬性到Content-Type再到request.getInputStream() .

程序更新後,發現從flash發送過來的請求流接收不到了,百思不得其解,網上查了查,發現了下面的文章:

 

還是一個異常引發的故事:

需要實現一個手機客戶端行爲分析的需求,手機客戶端需要上傳一些數據文件。手機客戶端通過http協議post方式上傳數據文件的時候,我們發現在服務器端無法通過request.getInputStream()獲取到相應的數據,調用request.getInputStream()讀取數據裏頭啥都木有。

 


經過各種嘗試我們注意到如下的情況:

1.在不做任何修改的情況下,調用request.getParameter()可以獲取到部分數據,即url拼接參數的數據。

2.在不做任何修改的情況下,如果在之前任何地方都不調用request.getParameter(),而是直接調用request.getInputStream()是可以獲取到數據的。

3.原來客戶端使用默認的請求頭Content-Type:application/x-www-form-urlencoded,修改此值爲multipart/form-data或者application/octet-stream之後,通過request.getInputStream()可以獲取到數據,即使之前調用過request.getParameter()。

 


最後的解決方法當然是客戶端修改Content-Type,因爲服務器端request.getInputStream()的方法不方便修改。今天具體分析下里頭的原理。

 

 

一.從form的enctype屬性到Content-Type


寫html的時候我們都知道form有個屬性enctype,默認值是application/x-www-form-urlencoded,這個值表示會將表單數據用&符號做一個簡單的拼接。例如:

 

POST /post_test.php HTTP/1.1 
Accept-Language: zh-CN
User-Agent: Mozilla/4.0 
Content-Type: application/x-www-form-urlencoded 
Host: 192.168.12.102
Content-Length: 42
Connection: Keep-Alive
Cache-Control: no-cache
 
title=test&content=%B3%AC%BC%B6%C5%AE%C9%FA&submit=post+article


 

title=test&content=%B3%AC%BC%B6%C5%AE%C9%FA&submit=post+article
我們注意到這個時候Content-Type爲application/x-www-form-urlencoded。

如果enctype的值爲multipart/form-data,這個值一般用於表單中包含文件上傳的情況,它會將表單中的數據使用一個boundary作爲分隔上傳。例如:

POST /post_test.php?t=1 HTTP/1.1
Accept-Language: zh-CN
User-Agent: Mozilla/4.0  
Content-Type: multipart/form-data; boundary=---------------------------7dbf514701e8
Accept-Encoding: gzip, deflate
Host: 192.168.12.102
Content-Length: 345
Connection: Keep-Alive
Cache-Control: no-cache
 
-----------------------------7dbf514701e8
Content-Disposition: form-data; name="title"
test
-----------------------------7dbf514701e8
Content-Disposition: form-data; name="content"
....
-----------------------------7dbf514701e8
Content-Disposition: form-data; name="submit"
post article
-----------------------------7dbf514701e8--


 

我們注意到這個時候Content-Type也相應的變爲multipart/form-data,同時後面還加上了分隔符boundary的描述。

所以,其實form的enctype屬性某種程度上決定了Content-Type值和請求body裏頭的數據格式。

詳細的可以參考:http://imzc.net/archives/131

 


二.從Content-Type到request.getInputStream()

 


上面說到了form的處理情況,但是其實如果我們不是使用瀏覽器,而是自己實現的客戶端來傳遞數據的話,這些頭信息就得都由自己處理。

所以上面就出現了,上傳文件的時候仍然使用了application/x-www-form-urlencoded的不標準用法。

但是爲啥Content-Type會影響request的處理呢?這得從request的一些實現說起。

 request.getParameter()、 request.getInputStream()、request.getReader()這三種方法是有衝突的,因爲流只能被讀一次。

 比如: 當form表單內容採用 enctype=application/x-www-form-urlencoded編碼時,先通過調用request.getParameter() 方法得到參數後,再調用 request.getInputStream()或request.getReader()已經得不到流中的內容,因爲在調用 request.getParameter()時系統可能對錶單中提交的數 據以流的形式讀了一次(原來是這樣),反之亦然。

當form表單內容採用 enctype=multipart/form-data編碼時,即使先調用request.getParameter()也得不到數據,但是這時調用 request.getParameter()方法對 request.getInputStream()或request.getReader()沒有衝突,即使已經調用了 request.getParameter()方法也 可以通過調用request.getInputStream()或request.getReader()得 到表單中的數據,而request.getInputStream()和request.getReader()在同 一個響應中是不能混合使用的,如果混合使用就會拋異常。

更多也可以參考:http://robert-liu.iteye.com/blog/713568

 

 

轉自:http://blog.csdn.net/shootyou/article/details/7182004

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章