HTTP的地址格式如下:
http_URL = "http:" "http://" host [ ":" port ] [ abs_path [ "?" query ]]
協(xié)議和host不分大小寫
HTTP消息
一個(gè)HTTP消息可能是request或者response消息笙瑟,兩種類型的消息都是由開始行(start-line)算灸,零個(gè)或多個(gè)header域,一個(gè)表示header域結(jié)束的空行(也就是锣笨,一個(gè)以CRLF為前綴的空行)刚梭,一個(gè)可能為空的消息主體(message-body)。一個(gè)合格的HTTP客戶端不應(yīng)該在消息頭或者尾添加多余的CRLF票唆,服務(wù)端也會(huì)忽略這些字符朴读。
header的值不包括任何前導(dǎo)或后續(xù)的LWS(線性空白),線性空白可能會(huì)出現(xiàn)在域值(filed-value)的第一個(gè)非空白字符之前或最后一個(gè)非空白字符之后走趋。前導(dǎo)或后續(xù)的LWS可能會(huì)被移除而不會(huì)改變域值的語意衅金。任何出現(xiàn)在filed-content之間的LWS可能會(huì)被一個(gè)SP(空格)代替。header域的順序不重要簿煌,但建議把常用的header放在前邊(協(xié)議里這么說的)氮唯。
Request消息
RFC2616中這樣定義HTTP Request 消息:
Request = Request-Line
*(( general-header
| request-header(跟本次請(qǐng)求相關(guān)的一些header)
| entity-header ) CRLF)(跟本次請(qǐng)求相關(guān)的一些header)
CRLF
[ message-body ]
一個(gè)HTTP的request消息以一個(gè)請(qǐng)求行開始,從第二行開始是header姨伟,接下來是一個(gè)空行惩琉,表示header結(jié)束,最后是消息體夺荒。
請(qǐng)求行的定義如下:
//請(qǐng)求行的定義
Request-Line = Method SP Request-URL SP HTTP-Version CRLF
//方法的定義
Method = "OPTIONS" | "GET" | "HEAD" |"POST" |"PUT" |"DELETE" |"TRACE" |"CONNECT" | extension-method
//資源地址的定義
Request-URI ="*" | absoluteURI | abs_path | authotity(CONNECT)
Request消息中使用的header可以是general-header或者request-header瞒渠,request-header(后邊會(huì)講解)良蒸。其中有一個(gè)比較特殊的就是Host,Host會(huì)與reuqest Uri一起來作為Request消息的接收者判斷請(qǐng)求資源的條件伍玖,方法如下:
1 嫩痰、 如果Request-URI是絕對(duì)地址(absoluteURI),這時(shí)請(qǐng)求里的主機(jī)存在于Request-URI里窍箍。任何出現(xiàn)在請(qǐng)求里Host頭域值應(yīng)當(dāng)被忽略串纺。
2 、 假如Request-URI不是絕對(duì)地址(absoluteURI)椰棘,并且請(qǐng)求包括一個(gè)Host頭域纺棺,則主機(jī)由該Host頭域值決定。
3 邪狞、假如由規(guī)則1或規(guī)則2定義的主機(jī)是一個(gè)無效的主機(jī)祷蝌,則應(yīng)當(dāng)以一個(gè)400(錯(cuò)誤請(qǐng)求)錯(cuò)誤消息返回。
Response消息
響應(yīng)消息跟請(qǐng)求消息幾乎一模一樣外恕,定義如下:
Response = Status-Line
*(( general-header
| response-header
| entity-header ) CRLF)
CRLF
[ message-body ]
可以看到杆逗,除了header不使用request-header之外,只有第一行不同鳞疲,響應(yīng)消息的第一行是狀態(tài)行罪郊,其中就包含大名鼎鼎的返回碼。
Status-Line的內(nèi)容首先是協(xié)議的版本號(hào)尚洽,然后跟著返回碼悔橄,最后是解釋的內(nèi)容,它們之間各有一個(gè)空格分隔腺毫,行的末尾以一個(gè)回車換行符作為結(jié)束癣疟。定義如下:
Status-Line = HTTP-Version SP Status-Code SP Reason-Phrase CRLF
返回碼
返回碼是一個(gè)3位數(shù),第一位定義的返回碼的類別潮酒,總共有5個(gè)類別睛挚,它們是:
- 1xx: Informational - Request received, continuing process
- 2xx: Success - The action was successfully received,
understood, and accepted
- 3xx: Redirection - Further action must be taken in order to complete the request
- 4xx: Client Error - The request contains bad syntax or cannot
be fulfilled
- 5xx: Server Error - The server failed to fulfill an apparently valid request
RFC2616中接著又給出了一系列返回碼的擴(kuò)展,這些都是我們平時(shí)會(huì)用到的急黎,但是那些只是示例扎狱,HTTP1.1不強(qiáng)制通信各方遵守這些擴(kuò)展的返回碼,通信各方在返回碼的實(shí)現(xiàn)上只需要遵守以上邊定義的這5種類別的定義勃教,意思就是淤击,返回碼的第一位要嚴(yán)格按照文檔中所述的來,其他的隨便定義故源。
任何人接收到一個(gè)不認(rèn)識(shí)的返回碼xyz污抬,都可以把它當(dāng)做x00來對(duì)待。對(duì)于不認(rèn)識(shí)的返回碼的響應(yīng)消息绳军,不可以緩存印机。
Header
RFC2616中定義了4種header類型矢腻,在通信各方都認(rèn)可的情況下,請(qǐng)求頭可以被擴(kuò)展的(可信的擴(kuò)展只能等到協(xié)議的版本更新)耳贬,如果接收者收到了一個(gè)不認(rèn)識(shí)的請(qǐng)求頭踏堡,這個(gè)頭將會(huì)被當(dāng)做實(shí)體頭猎唁。4種頭類型如下:
- 通用頭(General Header Fields):可用于request咒劲,也可用于response的頭,但不可作為實(shí)體頭诫隅,只能作為消息的頭腐魂。
general-header = Cache-Control ; Section 14.9
| Connection ; Section 14.10
| Date ; Section 14.18
| Pragma ; Section 14.32
| Trailer ; Section 14.40
| Transfer-Encoding ; Section 14.41
| Upgrade ; Section 14.42
| Via ; Section 14.45
| Warning ; Section 14.46
- 請(qǐng)求頭(Request Header Fields):被請(qǐng)求發(fā)起端用來改變請(qǐng)求行為的頭。
request-header = Accept ; Section 14.1
| Accept-Charset ; Section 14.2
| Accept-Encoding ; Section 14.3
| Accept-Language ; Section 14.4
| Authorization ; Section 14.8
| Expect ; Section 14.20
| From ; Section 14.22
| Host ; Section 14.23
| If-Match ; Section 14.24
| If-Modified-Since ; Section 14.25
| If-None-Match ; Section 14.26
| If-Range ; Section 14.27
| If-Unmodified-Since ; Section 14.28
| Max-Forwards ; Section 14.31
| Proxy-Authorization ; Section 14.34
| Range ; Section 14.35
| Referer ; Section 14.36
| TE ; Section 14.39
| User-Agent ; Section 14.43
- 響應(yīng)頭(Response Header Fields):被服務(wù)器用來對(duì)資源進(jìn)行進(jìn)一步的說明逐纬。
response-header = Accept-Ranges ; Section 14.5
| Age ; Section 14.6
| ETag ; Section 14.19
| Location ; Section 14.30
| Proxy-Authenticate ; Section 14.33
| Retry-After ; Section 14.37
| Server ; Section 14.38
| Vary ; Section 14.44
| WWW-Authenticate ; Section 14.47
- 實(shí)體頭(Entity Header Fields):如果消息帶有消息體蛔屹,實(shí)體頭用來作為元信息;如果沒有消息體豁生,就是為了描述請(qǐng)求的資源的信息兔毒。
entity-header = Allow ; Section 14.7
| Content-Encoding ; Section 14.11
| Content-Language ; Section 14.12
| Content-Length ; Section 14.13
| Content-Location ; Section 14.14
| Content-MD5 ; Section 14.15
| Content-Range ; Section 14.16
| Content-Type ; Section 14.17
| Expires ; Section 14.21
| Last-Modified ; Section 14.29
| extension-header
消息體(Message Body)和實(shí)體主體(Entity Body)
如果有Transfer-Encoding頭,那么消息體解碼完了就是實(shí)體主體甸箱,如果沒有Transfer-Encoding頭育叁,消息體就是實(shí)體主體。
message-body = entity-body
| <entity-body encoded as per Transfer-Encoding>
在request消息中芍殖,消息頭中含有Content-Length或者Transfer-Encoding豪嗽,標(biāo)識(shí)會(huì)有一個(gè)消息體跟在后邊。如果請(qǐng)求的方法不應(yīng)該含有消息體(如OPTION)豌骏,那么request消息一定不能含有消息體龟梦,即使客戶端發(fā)送過去,服務(wù)器也不會(huì)讀取消息體窃躲。
在response消息中计贰,是否存在消息體由請(qǐng)求方法和返回碼來共同決定。像1xx蒂窒,204躁倒,304不會(huì)帶有消息體。
消息體的長(zhǎng)度
消息體長(zhǎng)度的確定有一下幾個(gè)規(guī)則刘绣,它們順序執(zhí)行:
1. 所有不應(yīng)該返回內(nèi)容的Response消息都不應(yīng)該帶有任何的消息體樱溉,消息會(huì)在第一個(gè)空行就被認(rèn)為是終止了。
2. 如果消息頭含有Transfer-Encoding纬凤,且它的值不是identity福贞,那么消息體的長(zhǎng)度會(huì)使用chunked方式解碼來確定,直到連接終止停士。
3. 如果消息頭中有Content-Length挖帘,那么它就代表了entity-length和transfer-length完丽。如果同時(shí)含有Transfer-Encoding,則entity-length和transfer-length可能不會(huì)相等拇舀,那么Content-Length會(huì)被忽略逻族。
4. 如果消息的媒體類型是multipart/byteranges,并且transfer-length也沒有指定骄崩,那么傳輸長(zhǎng)度由這個(gè)媒體自己定義聘鳞。通常是收發(fā)雙發(fā)定義好了格式, HTTP1.1客戶端請(qǐng)求里如果出現(xiàn)Range頭域并且?guī)в卸鄠€(gè)字節(jié)范圍(byte-range)指示符要拂,這就意味著客戶端能解析multipart/byteranges響應(yīng)抠璃。
5. 如果是Response消息,也可以由服務(wù)器來斷開連接脱惰,作為消息體結(jié)束搏嗡。
從消息體中得到實(shí)體主體,它的類型由兩個(gè)header來定義拉一,Content-Type和Content-Encoding(通常用來做壓縮)采盒。如果有實(shí)體主體,則必須有Content-Type,如果沒有蔚润,接收方就需要猜測(cè)磅氨,猜不出來就是用application/octet-stream。
HTTP連接
HTTP1.1的連接默認(rèn)使用持續(xù)連接(persistent connection)抽碌,持續(xù)連接指的是悍赢,有時(shí)是客戶端會(huì)需要在短時(shí)間內(nèi)向服務(wù)端請(qǐng)求大量的相關(guān)的資源,如果不是持續(xù)連接货徙,那么每個(gè)資源都要建立一個(gè)新的連接左权,HTTP底層使用的是TCP,那么每次都要使用三次握手建立TCP連接痴颊,將造成極大的資源浪費(fèi)赏迟。
持續(xù)連接可以帶來很多的好處:
1. 使用更少的TCP連接,對(duì)通信各方的壓力更小蠢棱。
2. 可以使用管道(pipeline)來傳輸信息锌杀,這樣請(qǐng)求方不需要等待結(jié)果就可以發(fā)送下一條信息,對(duì)于單個(gè)的TCP的使用更充分泻仙。
3. 流量更小
4. 順序請(qǐng)求的延時(shí)更小糕再。
5. 不需要重新建立TCP連接就可以傳送error,關(guān)閉連接等信息玉转。
HTTP1.1的服務(wù)器使用TCP的流量控制來控制HTTP的流量突想,HTTP1.1的客戶端在收到服務(wù)器連接中發(fā)過來的error信息,就要馬上關(guān)閉此鏈接。關(guān)于HTTP連接還有很多細(xì)節(jié)猾担,之后再詳述袭灯。
WebSocket
只從RFC發(fā)布的時(shí)間看來,WebSocket要晚近很多绑嘹,HTTP 1.1是1999年稽荧,WebSocket則是12年之后了。WebSocket協(xié)議的開篇就說工腋,本協(xié)議的目的是為了解決基于瀏覽器的程序需要拉取資源時(shí)必須發(fā)起多個(gè)HTTP請(qǐng)求和長(zhǎng)時(shí)間的輪訓(xùn)的問題……而創(chuàng)建的姨丈。