HTTP 的請求報文分爲三個部分 請求行、請求頭和請求體,格式如圖:
一個典型的請求消息頭域,以下所示:php
POST/GET http://download.microtool.de:80/somedata.exe
Host: download.microtool.de
Accept:*/* Pragma: no-cache Cache-Control: no-cache Referer: http://download.microtool.de/ User-Agent:Mozilla/4.04[en](Win95;I;Nav) Range:bytes=554554-
請求行(Request Line)分爲三個部分:請求方法、請求地址和協議及版本,以CRLF(rn)結束。HTTP/1.1 定義的請求方法有8種:GET、POST、PUT、DELETE、PATCH、HEAD、OPTIONS、TRACE,最常的兩種GET和POST,若是是RESTful接口的話通常會用到GET、POST、DELETE、PUT。html
注意,僅有POST、PUT以及PATCH這三個動詞時會包含請求體,而GET、HEAD、DELETE、CONNECT、TRACE、OPTIONS這幾個動詞時不包含請求體。jquery
Header | 解釋 | 示例 |
---|---|---|
Accept | 指定客戶端可以接收的內容類型 | Accept: text/plain, text/html,application/json |
Accept-Charset | 瀏覽器能夠接受的字符編碼集。 | Accept-Charset: iso-8859-5 |
Accept-Encoding | 指定瀏覽器能夠支持的web服務器返回內容壓縮編碼類型。 | Accept-Encoding: compress, gzip |
Accept-Language | 瀏覽器可接受的語言 | Accept-Language: en,zh |
Accept-Ranges | 能夠請求網頁實體的一個或者多個子範圍字段 | Accept-Ranges: bytes |
Authorization | HTTP受權的受權證書 | Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ== |
Cache-Control | 指定請求和響應遵循的緩存機制 | Cache-Control: no-cache |
Connection | 表示是否須要持久鏈接。(HTTP 1.1默認進行持久鏈接) | Connection: close |
Cookie | HTTP請求發送時,會把保存在該請求域名下的全部cookie值一塊兒發送給web服務器。 | Cookie: $Version=1; Skin=new; |
Content-Length | 請求的內容長度 | Content-Length: 348 |
Content-Type | 請求的與實體對應的MIME信息 | Content-Type: application/x-www-form-urlencoded |
Date | 請求發送的日期和時間 | Date: Tue, 15 Nov 2010 08:12:31 GMT |
Expect | 請求的特定的服務器行爲 | Expect: 100-continue |
From | 發出請求的用戶的Email | From: user@email.com |
Host | 指定請求的服務器的域名和端口號 | Host: www.zcmhi.com |
If-Match | 只有請求內容與實體相匹配纔有效 | If-Match: 「737060cd8c284d8af7ad3082f209582d」 |
If-Modified-Since | 若是請求的部分在指定時間以後被修改則請求成功,未被修改則返回304代碼 | If-Modified-Since: Sat, 29 Oct 2010 19:43:31 GMT |
If-None-Match | 若是內容未改變返回304代碼,參數爲服務器先前發送的Etag,與服務器迴應的Etag比較判斷是否改變 | If-None-Match: 「737060cd8c284d8af7ad3082f209582d」 |
If-Range | 若是實體未改變,服務器發送客戶端丟失的部分,不然發送整個實體。參數也爲Etag | If-Range: 「737060cd8c284d8af7ad3082f209582d」 |
If-Unmodified-Since | 只在實體在指定時間以後未被修改才請求成功 | If-Unmodified-Since: Sat, 29 Oct 2010 19:43:31 GMT |
Max-Forwards | 限制信息經過代理和網關傳送的時間 | Max-Forwards: 10 |
Pragma | 用來包含實現特定的指令 | Pragma: no-cache |
Proxy-Authorization | 鏈接到代理的受權證書 | Proxy-Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ== |
Range | 只請求實體的一部分,指定範圍 | Range: bytes=500-999 |
Referer | 先前網頁的地址,當前請求網頁緊隨其後,即來路 | Referer: http://www.zcmhi.com/archives... |
TE | 客戶端願意接受的傳輸編碼,並通知服務器接受接受尾加頭信息 | TE: trailers,deflate;q=0.5 |
Upgrade | 向服務器指定某種傳輸協議以便服務器進行轉換(若是支持) | Upgrade: HTTP/2.0, SHTTP/1.3, IRC/6.9, RTA/x11 |
User-Agent | User-Agent的內容包含發出請求的用戶信息 | User-Agent: Mozilla/5.0 (Linux; X11) |
Via | 通知中間網關或代理服務器地址,通訊協議 | Via: 1.0 fred, 1.1 nowhere.com (Apache/1.1) |
Warning | 關於消息實體的警告信息 | Warn: 199 Miscellaneous warning |
根據應用場景的不一樣,HTTP請求的請求體有三種不一樣的形式。angularjs
移動開發者常見的,請求體是任意類型,服務器不會解析請求體,請求體的處理須要本身解析,如 POST JSON時候就是這類。
web
application/json 這個 Content-Type 做爲響應頭你們確定不陌生。實際上,如今愈來愈多的人把它做爲請求頭,用來告訴服務端消息主體是序列化後的 JSON 字符串。因爲 JSON 規範的流行,除了低版本 IE 以外的各大瀏覽器都原生支持 JSON.stringify,服務端語言也都有處理 JSON 的函數,使用 JSON 不會趕上什麼麻煩。ajax
JSON 格式支持比鍵值對複雜得多的結構化數據,這一點也頗有用。記得我幾年前作一個項目時,須要提交的數據層次很是深,我就是把數據 JSON 序列化以後來提交的。不過當時我是把 JSON 字符串做爲 val,仍然放在鍵值對裏,以 x-www-form-urlencoded 方式提交。chrome
Google 的 AngularJS 中的 Ajax 功能,默認就是提交 JSON 字符串。例以下面這段代碼:json
JSvar data = {'title':'test', 'sub' : [1,2,3]}; $http.post(url, data).success(function(result) { ... });
最終發送的請求是:數組
BASHPOST 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 時,從 php://input
裏得到原始輸入流,再 json_decode
成對象。一些 php 框架已經開始這麼作了。瀏覽器
固然 AngularJS 也能夠配置爲使用 x-www-form-urlencoded 方式提交數據。若有須要,能夠參考這篇文章。
個人博客以前提到過 XML-RPC(XML Remote Procedure Call)。它是一種使用 HTTP 做爲傳輸協議,XML 做爲編碼方式的遠程調用規範。典型的 XML-RPC 請求是這樣的:
HTMLPOST http://www.example.com HTTP/1.1
Content-Type: text/xml
<?xml version="1.0"?> <methodCall> <methodName>examples.getStateName</methodName> <params> <param> <value><i4>41</i4></value> </param> </params> </methodCall>
XML-RPC 協議簡單、功可以用,各類語言的實現都有。它的使用也很普遍,如 WordPress 的 XML-RPC Api,搜索引擎的 ping 服務等等。JavaScript 中,也有現成的庫支持以這種方式進行數據交互,能很好的支持已有的 XML-RPC 服務。不過,我我的以爲 XML 結構仍是過於臃腫,通常場景用 JSON 會更靈活方便。
這算是最多見的 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;這裏的格式要求就是URL中Query String的格式要求:多個鍵值對之間用&鏈接,鍵與值以前用=鏈接,且只能用ASCII字符,非ASCII字符需使用UrlEncode編碼。大部分服務端語言都對這種方式有很好的支持。例如 PHP 中,$_POST['title'] 能夠獲取到 title 的值,$_POST['sub'] 能夠獲得 sub 數組。
第三種請求體的請求體被分紅爲多個部分,文件上傳時會被使用,這種格式最早應該是被用於郵件傳輸中,每一個字段/文件都被boundary(Content-Type中指定)分紅單獨的段,每段以-- 加 boundary開頭,而後是該段的描述頭,描述頭以後空一行接內容,請求結束的標製爲boundary後面加--,結構見下圖:
區分是否被當成文件的關鍵是Content-Disposition是否包含filename,由於文件有不一樣的類型,因此還要使用Content-Type指示文件的類型,若是不知道是什麼類型取值能夠爲application/octet-stream表示該文件是個二進制文件,若是不是文件則Content-Type能夠省略。
咱們使用表單上傳文件時,必須讓 <form> 表單的 enctyped
等於 multipart/form-data。直接來看一個請求示例:
BASHPOST 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" Content-Type: image/png PNG ... content of chrome.png ... ------WebKitFormBoundaryrGKCBY7qhFd3TrwA--
這個例子稍微複雜點。首先生成了一個 boundary 用於分割不一樣的字段,爲了不與正文內容重複,boundary 很長很複雜。而後 Content-Type 裏指明瞭數據是以 multipart/form-data 來編碼,本次請求的 boundary 是什麼內容。消息主體裏按照字段個數又分爲多個結構相似的部分,每部分都是以 --boundary
開始,緊接着是內容描述信息,而後是回車,最後是字段具體內容(文本或二進制)。若是傳輸的是文件,還要包含文件名和文件類型信息。消息主體最後以 --boundary--
標示結束。關於 multipart/form-data 的詳細定義,請前往 rfc1867 查看。
這種方式通常用來上傳文件,各大服務端語言對它也有着良好的支持。
上面提到的這兩種 POST 數據的方式,都是瀏覽器原生支持的,並且現階段標準中原生 <form> 表單也只支持這兩種方式(經過 <form> 元素的enctype
屬性指定,默認爲 application/x-www-form-urlencoded
。其實 enctype
還支持 text/plain
,不過用得很是少)。
隨着愈來愈多的 Web 站點,尤爲是 WebApp,所有使用 Ajax 進行數據交互以後,咱們徹底能夠定義新的數據提交方式,給開發帶來更多便利。
網頁中的表單使用POST方法提交時,數據內容的類型是 application/x-www-form-urlencoded,這種類型會:
1.字符"a"-"z","A"-"Z","0"-"9",".","-","*",和"_" 都不會被編碼;
2.將空格轉換爲加號 (+)
3.將非文本內容轉換成"%xy"的形式,xy是兩位16進制的數值;
4.在每一個 name=value 對之間放置 & 符號。
web設計者面臨的衆多難題之一即是怎樣處理不一樣操做系統間的差別性。這些差別性能引發URL方面的問題:例如,一些操做系統容許文件名中含有空格符,有些又不容許。大多數操做系統不會認爲文件名中含有符號「#」會有什麼特殊含義;可是在一個URL中,符號「#」表示該文件名已經結束,後面會緊跟一個fragment(部分)標識符。其餘的特殊字符,非字母數字字符集,它們在URL或另外一個操做系統上都有其特殊的含義,表述着類似的問題。爲了解決這些問題,咱們在URL中使用的字符就必須是一個ASCII字符集的固定字集中的元素,具體以下:
1.大寫字母A-Z
2.小寫字母a-z
3.數字 0-9
4.標點符 - _ . ! ~ * ' (和 ,)
諸如字符: / & ? @ # $ + = 和 %也能夠被使用,可是它們各有其特殊的用途,若是一個文件名包括了這些字符( / & ? @ # $ + = %),這些字符和全部其餘字符就應該被編碼。
編碼過程很是簡單,任何字符只要不是ASCII碼數字,字母,或者前面提到的標點符,它們都將被轉換成字節形式,每一個字節都寫成這種形式:一個「%」後面跟着兩位16進制的數值。空格是一個特殊狀況,由於它們太日常了。它除了被編碼成「%20」之外,還能編碼爲一個「+」。加號(+)自己被編碼爲%2B。當/ # = & 和?做爲名字的一部分來使用時,而不是做爲URL部分之間的分隔符來使用時,它們都應該被編碼。
WARNING這種策略在存在大量字符集的異構環境中效果不甚理想。例如:在U.S. Windows 系統中, é 被編碼爲 %E9. 在 U.S. Mac中被編碼爲%8E。這種不肯定性的存在是現存的URI的一個明顯的不足。因此在未來URI的規範當中應該經過國際資源標識符(IRIs)進行改善。
類URL並不自動執行編碼或解碼工做。你能生成一個URL對象,它能夠包括非法的ASCII和非ASCII字符和/或%xx。當用方法getPath() 和toExternalForm( ) 做爲輸出方法時,這種字符和轉移符不會自動編碼或解碼。你應對被用來生成一個URL對象的字符串對象負責,確保全部字符都會被恰當地編碼。