application/x- www-form-urlencoded是Post請求默認的請求體內容類型,也是form表單默認的類型。Servlet API規范中對該類型的請求內容提供了request.getParameter()方法來獲取請求參數值。但當請求內容不是該類型時,需要調用request.getInputStream()或request.getReader()方法來獲取請求內容值。
當請求體內容(注意:get請求沒有請求體)類型是application/x- www-form-urlencoded時也可以直接調用request.getInputStream()或request.getReader()方法獲取到請求內容再解析出具體都參數,但前提是還沒調用request.getParameter()方法(先寫了getParameter()方法,再用getReader()方法不能取到數據)。此時當request.getInputStream()或request.getReader()獲取到請求內容后,無法再調request.getParameter()獲取請求內容。即對該類型的請求,三個方法互斥,只能調其中一個。今天遇到一個Controller請求經過Spring MVC 的RequestMapping處理后,只能通過request.getParameter()獲取到參數、無法通過request.getInputStream()和request.getReader()讀取內容很可能就是因為在請求經過Spring MVC時已調用過request.getParameter()方法的原因。
注意:在一個請求鏈中,請求對象被前面對象方法中調用request.getInputStream()或request.getReader()獲取過內容后,后面的對象方法里再調用這兩個方法也無法獲取到客戶端請求的內容,但是調用request.getParameter()方法獲取過內容后,后面的對象方法里依然可以調用它獲取到參數的內容。
當請求體內容是其它類型時,比如 multipart/form-data或application/json時,無法通過request.getParameter()獲取到請求內容,此時只能通過request.getInputStream()和request.getReader()方法獲取請求內容,此時調用request.getParameter()也不會影響第一次調用request.getInputStream()或request.getReader()獲取到請求內容。
request.getInputStream()返回請求內容字節流,多用於文件上傳,request.getReader()是對前者返回內容的封裝,可以讓調用者更方便字符內容的處理(不用自己先獲取字節流再做字符流的轉換操作)。
POST 的三種常用 Content-Type (get沒有請求體)
POST 是日常開發中非常常用的數據傳輸方法,請求頭中的 Content-Type 指示了在一次 POST 請求中,服務器端應該如何解析客戶端傳遞過來的數據。對於 web 開發來說, 以下三種 Content-Type 是最為常見的:
1
application/x-www-form-urlencoded
1.作為 <form /> 元素的默認 Content-Type 設定(enctype 屬性),application/x-www-form-urlencoded 可能是被使用得最為廣泛的一種數據編碼方式。一次application/x-www-form-urlencoded 的 POST 請求內容大致如下:
名圖HTTP請求報文
中間的空行是請求頭和請求體的分隔符,請求體的形式和 GET 請求的參數(Query String) 一樣,同樣是將內容進行百分比編碼。
在 chrome 調試工具中能看到發送出去的信息如下:
2.接收方式
對於 springmvc 來說,主要通過以下兩種方式來接收 Content-Type 為 application/x-www-form-urlencoded 的數據:
-
直接根據參數接收
-
作為 domain 接收
當作為 domain 接收時,springmvc 無法對 domain 中的復雜數據類型進行解析,在這種情況下,使用 application/json 是更好的選擇。
2
application/json
空行同樣是請求頭和請求體的分隔符, application/json 的不同在於,請求體的內容是 JSON 字符串。
chrome 調試工具中顯示的內容如下:
2.接收方式
對於一個 Content-Type 為 application/json 的請求, springmvc 中可以使用 RequestBody 參數注解,請求體中的 JSON 字符串將被嘗試解析為指定的對象,同時 RequestBody 也接受參數用於指示解析過程中是否允許對象為null。
3
application/x-www-form-urlencoded
1.用於文件上傳的 Content-Type, 比較特殊的是,對於這樣的 Content-Type 設定,瀏覽器會生成一個比較復雜且隨機的boundary,並追加在 Content-Type 之后,用於分割請求體中的文件內容。
request.getParameter()-----post表單/ajax傳對象
request.getInputStream();// 后面這2種可以獲取post所有提交的數據
request.getReader()
// 方法二 public static void ReadAsChars2(HttpServletRequest request) { StringBuilder sb = new StringBuilder("--------"); InputStream is = null; try { is = request.getInputStream(); sb = new StringBuilder(); byte[] b = new byte[4096]; for (int n; (n = is.read(b)) != -1;) { sb.append(new String(b, 0, n)); } } catch (IOException e) { e.printStackTrace(); } finally { if (null != is) { try { is.close(); } catch (IOException e) { e.printStackTrace(); } } } System.out.println("#"+sb); } // 字符串讀取 // 方法一 public static String ReadAsChars(HttpServletRequest request) { BufferedReader br = null; StringBuilder sb = new StringBuilder(""); try { br = request.getReader(); String str; while ((str = br.readLine()) != null) { sb.append(str); } br.close(); } catch (IOException e) { e.printStackTrace(); } finally { if (null != br) { try { br.close(); } catch (IOException e) { e.printStackTrace(); } } } return sb.toString(); } }