各種content-type情況下的請求報文結構以及後臺取參方式


本文總體脈絡,先從http請求報文入手,引出不同形式的content-type是如何組織參數的。接下來對四種較爲常見的content-type 下組參方式進行介紹。最後介紹不同的content-type,後臺應該如何取參。

http請求報文分析

HTTP 協議是以 ASCII 碼傳輸,建立在 TCP/IP 協議之上的應用層協議。 HTTP 請求分爲三個部分:狀態行、請求頭、消息主體(請求數據)。類似於下面這樣:

在這裏插入圖片描述

介紹get&post&head請求方法的報文

(HTTP協議的請求方法有GET、POST、HEAD、PUT、DELETE、OPTIONS、TRACE、CONNECT)

get方法報文

GET /search?hl=zh-CN&source=hp&q=domety&aq=f&oq= HTTP/1.1  
Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, application/x-silverlight, application/x-shockwave-flash, */*  
Referer: <a href="http://www.google.cn/">http://www.google.cn/</a>  
Accept-Language: zh-cn  
Accept-Encoding: gzip, deflate  
User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 2.0.50727; TheWorld)  
Host: <a href="http://www.google.cn">www.google.cn</a>  
Connection: Keep-Alive  
Cookie: PREF=ID=80a06da87be9ae3c:U=f7167333e2c3b714:NW=1:TM=1261551909:LM=1261551917:S=ybYcq2wpfefs4V9g; NID=31=ojj8d-IygaEtSxLgaJmqSjVhCspkviJrB6omjamNrSm8lZhKy_yMfO2M4QMRKcH1g0iQv9u-2hfBW7bUFwVh7pGaRUb0RnHcJU37y-FxlRugatx63JLv7CWMD6UB_O_r

post方法報文

POST /search HTTP/1.1  
Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, application/x-silverlight, application/x-shockwave-flash, */*  
Referer: <a href="http://www.google.cn/">http://www.google.cn/</a>  
Accept-Language: zh-cn  
Accept-Encoding: gzip, deflate  
User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 2.0.50727; TheWorld)  
Host: <a href="http://www.google.cn">www.google.cn</a>  
Connection: Keep-Alive  
Cookie: PREF=ID=80a06da87be9ae3c:U=f7167333e2c3b714:NW=1:TM=1261551909:LM=1261551917:S=ybYcq2wpfefs4V9g; NID=31=ojj8d-IygaEtSxLgaJmqSjVhCspkviJrB6omjamNrSm8lZhKy_yMfO2M4QMRKcH1g0iQv9u-2hfBW7bUFwVh7pGaRUb0RnHcJU37y-FxlRugatx63JLv7CWMD6UB_O_r  

hl=zh-CN&source=hp&q=domety

head方法

HEAD就像GET,只不過服務端接受到HEAD請求後只返回響應頭,而不會發送響應內容。當我們只需要查看某個頁面的狀態的時候,使用HEAD是非常高效的,因爲在傳輸的過程中省去了頁面內容。

不同的content-type如何組織參數

數據發送出去,還要服務端解析成功纔有意義。一般服務端語言如 java,php、python 等,都內置了自動解析常見數據格式的功能。服務端通常是根據請求頭(headers)中的 Content-Type(比如java application/x-www-form-urlencoded) 字段來獲知請求中的消息主體是用何種方式編碼,再對主體進行解析。一般get請求不會設置content-type,get請求的參數都是帶在url後面,直接取,只有post方法的時候,我們一般才考慮body裏面的參數組織類型,也就是content-type。下面就正式開始介紹Content-Type。

application/x-www-form-urlencoded

這應該是最常見的 POST 提交數據的方式了。瀏覽器的原生 form 表單,如果不設置 enctype 屬性,那麼最終就會以 application/x-www-form-urlencoded 方式提交數據。請求類似於下面這樣(無關的請求頭在本文中都省略掉了):

POST http://www.example.com HTTP/1.1
Content-Type: application/x-www-form-urlencoded;charset=utf-8

title=test&sub%5B%5D=1&sub%5B%5D=2&sub%5B%5D=3
首先,Content-Type 被指定爲 application/x-www-form-urlencoded;其次,提交的數據按照 key1=val1&key2=val2 的方式進行編碼,key 和 val 都進行了 URL 轉碼。大部分服務端語言都對這種方式有很好的支持。

很多時候,我們用 Ajax 提交數據時,也是使用這種方式。例如 JQuery 和 QWrap 的 Ajax,Content-Type 默認值都是「application/x-www-form-urlencoded;charset=utf-8」。注意,這裏的參數都是放在body裏面的。

multipart/form-data

這又是一個常見的 POST 數據提交的方式。我們使用表單上傳文件時,必須讓 form 的 enctyped 等於這個值。直接來看一個請求示例:

POST http://www.example.com HTTP/1.1
Content-Type:multipart/form-data; boundary=—-WebKitFormBoundaryrGKCBY7qhFd3TrwA //參數分隔符

——WebKitFormBoundaryrGKCBY7qhFd3TrwA
Content-Disposition: form-data; name=”text” //文本型參數

title
——WebKitFormBoundaryrGKCBY7qhFd3TrwA
Content-Disposition: form-data; name=”file”; filename=”chrome.png” //文件型參數,都是放在body裏面的
Content-Type: image/png

PNG … content of chrome.png …
——WebKitFormBoundaryrGKCBY7qhFd3TrwA–

首先生成了一個 boundary(這裏是 —-WebKitFormBoundaryrGKCBY7qhFd3TrwA) 用於分割不同的字段,爲了避免與正文內容重複,boundary 很長很複雜。然後 Content-Type 裏指明瞭數據是以 mutipart/form-data 來編碼,本次請求的 boundary 是什麼內容。消息主體裏按照字段個數又分爲多個結構類似的部分,每部分都是以 –boundary 開始,緊接着內容描述信息,然後是回車,最後是字段具體內容(文本或二進制)。如果傳輸的是文件,還要包含文件名和文件類型信息。消息主體最後以 –boundary– 標示結束。

這種方式一般用來上傳文件。

上面提到的這兩種 POST 數據的方式,都是瀏覽器原生支持的,而且現階段原生 form 表單也只支持這兩種方式。但是隨着越來越多的 Web 站點,尤其是 WebApp,全部使用 Ajax 進行數據交互之後,我們完全可以定義新的數據提交方式,給開發帶來更多便利。

application/json

application/json 這個 Content-Type 作爲響應頭大家肯定不陌生。實際上,現在越來越多的人把它作爲請求頭,用來告訴服務端消息主體是序列化後的 JSON 字符串。由於 JSON 規範的流行,除了低版本 IE 之外的各大瀏覽器都原生支持 JSON.stringify,服務端語言也都有處理 JSON 的函數,使用 JSON 不會遇上什麼麻煩。

JSON 格式支持比鍵值對複雜得多的結構化數據,這一點也很有用。

Google 的 AngularJS 中的 Ajax 功能,默認就是提交 JSON 字符串。例如下面這段代碼:

var data = {‘title’:’test’, ‘sub’ : [1,2,3]};
$http.post(url, data).success(function(result) {

});
最終發送的請求是:

POST http://www.example.com HTTP/1.1
Content-Type: application/json;charset=utf-8

{“title”:”test”,”sub”:[1,2,3]} //參數所在位置,後臺一般從流裏面取參數。
這種方案,可以方便的提交複雜的結構化數據,特別適合 RESTful 的接口。各大抓包工具如 Chrome 自帶的開發者工具、Firebug、Fiddler,都會以樹形結構展示 JSON 數據,非常友好。但也有些服務端語言還沒有支持這種方式,例如 php 就無法通過 $_POST 對象從上面的請求中獲得內容。這時候,需要自己動手處理下:在請求頭中 Content-Type 爲 application/json 時,後臺一般從流裏面取參數。

text/xml

XML-RPC(XML Remote Procedure Call)協議。它是一種使用 HTTP 作爲傳輸協議,XML 作爲編碼方式的遠程調用規範。典型的 XML-RPC 請求是這樣的:

POST http://www.example.com HTTP/1.1
Content-Type: text/xml

examples.getStateName 41

XML-RPC 協議簡單、功能夠用,各種語言的實現都有。它的使用也很廣泛,如 WordPress 的 XML-RPC Api,搜索引擎的 ping 服務等等。JavaScript 中,也有現成的庫支持以這種方式進行數據交互,能很好的支持已有的 XML-RPC 服務。不過,我個人覺得 XML 結構還是過於臃腫,一般場景用 JSON 會更靈活方便。

不同contentType 在springMvc下支持的取參方式

multipart/form-data

  • method 是post 並且content-ytpe 是 multipart/form-data ,請求中既可以攜帶文件,又可以攜帶參數。其中參數以鍵值對的方式傳遞,參數之間、參數與文件之間以 content-disposition 分隔;
    後臺取參方式
@RequestMapping(value = "/imgService",method = RequestMethod.POST)
public ResponseData uploadImg(@RequestParam("file") MultipartFile file,@RequestParam("desc") String desc ) {
}

application/x-www-form-urlencoded

  • method 是post 並且content-ytpe 是 application/x-www-form-urlencoded 只能上傳參數,不能攜帶文件,參數 xxx=xxx&xxx=xxx 的方式被組織在一起,放在body裏面;
    後臺取參方式
@RequestMapping(value = "/sms/smsCode", method = RequestMethod.POST)
public ResponseData smsCode(@RequestParam("type") Integer type,
                   @RequestParam("phone") String phone,
                   @RequestParam("sign") String sign) {
}

application/json

  • method 是post & application/json 只能上傳參數,不能攜帶文件,參數不被特殊組織,保持原 JSON 字符串的形式。
    後臺取參方式
@PostMapping(value = "/pay")
String couponPay(@RequestBody CouponPayV1Dto couponPayDto)

說明:儘管後臺取參的方式多種多樣,有從request對象取,有從inputStream中取,上面介紹的只是比較常見的方式。
補充:不同的content-type後臺對於參數的封裝和取參方式不同,application/json下是從流裏面取參。

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