HTTP知識點總結(jié)

最近互聯(lián)網(wǎng)這個圈子不是很太平,繼阿里縮招降薪,導(dǎo)致很多同學(xué)“被擁抱變化”之后,百度也宣布暫時停止社招了。于是有人疾呼“Winter is coming”,有人跟風(fēng)有人反駁,一時唇槍舌劍,熱鬧得緊。不過身為一名技術(shù)人員,這些言論看看也就是了,市場或許真的會起變化,但也不見得是壞事,大浪淘沙,有能耐的總會留下。人常說站在風(fēng)口,豬也能飛。如果風(fēng)真的停了,那摔死的也就是些飛豬。像我這種,壓根沒站在風(fēng)口也從沒起飛的豬,還是腳踏實地加緊鍛煉,爭取更快更高更強好了。

唉扯遠了,說點實在的吧。Web相關(guān)的開發(fā)人員應(yīng)該都知道HTTP協(xié)議的重要性,無論是做后端還是前端,安卓還是iOS,都要跟HTTP打交道。想必用Fiddler調(diào)試Web API的時候,對返回的各種4xx、5xx狀態(tài)碼感到一頭霧水絕不是什么愉快的體驗。最近也是復(fù)習(xí)了一些相關(guān)的知識,今天就總結(jié)一下。

雖然我們有B/S(Browser/Server)結(jié)構(gòu)、C/S(Client/Server)結(jié)構(gòu)這樣的說法來區(qū)分瀏覽器-服務(wù)器通信和客戶端-服務(wù)器通信,不過說到底只要是通過發(fā)送請求獲取服務(wù)器資源的一方,無論是Web瀏覽器還是移動App抑或是桌面應(yīng)用,其實都可以算是客戶端。而Web使用名為HTTP(HyperText Transfer Protocol,超文本傳輸協(xié)議)的協(xié)議作為規(guī)范,來完成從客戶端到服務(wù)器端的一系列操作流程。所謂協(xié)議,便是規(guī)則的約定,是一些既定的標準,我們這些開發(fā)者,只要遵守并好好使用就是了。不過說到HTTP么還是要先說下TCP/IP協(xié)議族。

TCP/IP協(xié)議族

通常所說的網(wǎng)絡(luò)(包括互聯(lián)網(wǎng)),是在TCP/IP協(xié)議族的基礎(chǔ)上運作的,而HTTP是它的一個子集。TCP/IP協(xié)議族可以分為4層,分別是應(yīng)用層、傳輸層、網(wǎng)絡(luò)層和鏈路層。下面分別介紹一下各層的作用:

  • 應(yīng)用層:決定了向用戶提供應(yīng)用服務(wù)時通信的活動。FTP(File Transfer Protocol, 文件傳輸協(xié)議)、DNS(Domain Name System,域名系統(tǒng))和HTTP都屬于該層。
  • 傳輸層:提供處于網(wǎng)絡(luò)連接中的兩臺計算機之間的數(shù)據(jù)傳輸。TCP(Transmission Control Protocol,傳輸控制協(xié)議)和UDP(User Data Protocol,用戶數(shù)據(jù)協(xié)議)都屬于該層。
  • 網(wǎng)絡(luò)層:用來處理網(wǎng)絡(luò)上流動的數(shù)據(jù)包。數(shù)據(jù)包是網(wǎng)絡(luò)傳輸?shù)淖钚?shù)據(jù)單位。該層規(guī)定了通過怎樣的路徑(所謂的傳輸路線)到達對方計算機,并把數(shù)據(jù)包傳給對方。與對方計算機之間通過多臺計算機或網(wǎng)絡(luò)設(shè)備進行傳輸時,網(wǎng)絡(luò)層所起的作用就是在眾多的選項內(nèi)選擇一條傳輸路線。
  • 鏈路層:用來處理網(wǎng)絡(luò)的硬件部分,包括操作系統(tǒng)、硬件的設(shè)備驅(qū)動、NIC(Network Interface Card,網(wǎng)卡)、光纖、諸如連接器之類的傳輸媒介等物理可見部分。

三次握手

我們知道TCP和UDP主要的區(qū)別是UDP只負責發(fā)送,不確保一定送達;而TCP提供可靠的字節(jié)流服務(wù)(Byte Stream Service),采用三次握手策略確保數(shù)據(jù)送達。三次握手的過程使用了TCP 標志——SYN(synchronize)和ACK(acknowledgement):

  1. 發(fā)送端發(fā)送一個帶SYN標志的數(shù)據(jù)包給對方。
  2. 接收端收到后,回傳一個帶有SYN/ACK標志的數(shù)據(jù)包以示傳達確認信息。
  3. 發(fā)送端回傳一個帶ACK標志的數(shù)據(jù)包,表示握手結(jié)束。

HTTP通信

利用TCP/IP協(xié)議族進行網(wǎng)絡(luò)通信時,會通過分層順序與對方進行通訊。以HTTP舉例來說,過程是這樣的:

  1. 客戶端在應(yīng)用層(HTTP協(xié)議)發(fā)出一項想看某個Web頁面的HTTP請求
  2. 在傳輸層(TCP協(xié)議)把從應(yīng)用層處收到的數(shù)據(jù)(HTTP請求報文)進行分割,并在各個報文上打上標記序號及端口號后轉(zhuǎn)發(fā)給網(wǎng)絡(luò)層。
  3. 在網(wǎng)絡(luò)層(IP協(xié)議),增加作為通信目的地MAC地址后轉(zhuǎn)發(fā)給鏈路層。

經(jīng)過以上步驟,一個網(wǎng)絡(luò)請求就準備齊全了。經(jīng)過網(wǎng)絡(luò)傳輸之后,接收端的服務(wù)器在鏈路層接收到數(shù)據(jù),按序往上層發(fā)送,一直到應(yīng)用層。到了應(yīng)用層才算真正接收到由客戶端發(fā)送過來的HTTP請求。

發(fā)送端在層與層之間傳輸數(shù)據(jù)時,每經(jīng)過一層必定會被打上一個該層所屬的首部信息;反之,接收端在層與層傳輸數(shù)據(jù)時,每經(jīng)過一層時會把對應(yīng)的首部消去。這種把數(shù)據(jù)信息包裝起來的做法,也叫封裝(encapsulate)。

HTTP請求

HTTP協(xié)議用于客戶端與服務(wù)器端之間的通信,協(xié)議規(guī)定,請求從客戶端發(fā)出,最后服務(wù)器端響應(yīng)該請求并返回。來看一個請求報文的例子:

GET /search.jsp HTTP/1.1
Host: g.hxgoogle.com

起始行的GET是一個HTTP動詞,也稱為方法(method),它可以指定請求的資源按期望產(chǎn)生某種行為,隨后的字符串/search.jsp指明了請求訪問的資源對象,稱為請求URI(request-URI),HTTP/1.1即HTTP的版本號,用來提示客戶端使用的HTTP協(xié)議功能。所以這段報文的意思翻譯一下是這樣的:請求用GET方法訪問域名為g.hxgoogle.com的服務(wù)器上的/search.jsp頁面資源。

一個完整的請求報文由Header和Body組成,Header包括請求方法、請求URI、協(xié)議版本、可選的請求首部字段等,Body指報文主體。下面重點介紹一下請求URI和HTTP方法。

URI和URL

URI表示統(tǒng)一資源標識符,是Uniform Resource Identifier的縮寫。RFC2396(RFC,Request for Comments,征求修正意見書,一些指定HTTP協(xié)議技術(shù)標準的文檔)分別對這三個單詞進行了如下定義:

  • Uniform:規(guī)定統(tǒng)一的格式可方便處理多種不同類型的資源,而不用根據(jù)上下文環(huán)境來識別資源指定的訪問方式。另外,加入新增的協(xié)議方案(如http:或ftp:)也更容易。
  • Resource:資源的定義是“可標識的任何東西”。資源不僅可以是單一的,也可以是個集合體。
  • Identifier:用來表示可標識的對象。也稱為標識符。

綜上所述,URI就是由某個協(xié)議方案(如http、ftp)表示的資源的定位標識符。如下列舉幾種URI的例子:

ftp://ftp.is.co.za/rfc/rfc1808.txt
http://www.ietf.org/rfc/rfc2396.txt
ldap://[2001:db8::7]/c=GB?objectClass?one
mailto:John.Doe@example.com
tel:+1-816-555-1212

URI用字符串標識某一互聯(lián)網(wǎng)資源,而我們相對來說更熟悉的URL(UniformResource Locator,統(tǒng)一資源定位符)則是表示資源的地點。顯然URL是URI的子集,而在我們大部分日常使用場景下,說到URL和URI的時候其實表示的是一個意思。

HTTP方法

我們最常用的HTTP方法是GET和POST,這導(dǎo)致很多人以為HTTP方法只有GET和POST。這是不對的,這些年RESTful API非常流行,所以作為Web開發(fā)人員至少還應(yīng)該知道PUT和DELETE。當然HTTP方法并不只有這么幾種,下面介紹幾種HTTP/1.1中的方法:

  • GET:請求訪問已被URI識別的資源,資源經(jīng)服務(wù)器端解析后返回響應(yīng)內(nèi)容。
  • POST:雖然GET方法也可以在Body中包含內(nèi)容進行傳輸,不過一般不用,而是使用POST方法。POST在RESTful架構(gòu)中一般用來修改資源。
  • PUT:用于傳輸資源到URI指定位置進行保存。由于PUT方法自身不帶驗證機制,存在安全問題,因此一般Web網(wǎng)站不使用該方法。若配合Web應(yīng)用程序的驗證機制或采用RESTful架構(gòu)設(shè)計,可能會開放使用。PUT在RESTful架構(gòu)中一般用來添加資源。
  • DELETE:刪除資源。與PUT情況類似,一般不開放。
  • HEAD:獲得報文首部(Header),用于確認URI的有效性及資源的更新日期等。
  • TRACE:追蹤路徑。發(fā)送請求時,在請求Header中加上Max-Forwards字段,譬如Max-Forwards: 2這樣,每經(jīng)過一個服務(wù)器就將該數(shù)字減1,當數(shù)字為0時停止傳輸,最后接收到請求的服務(wù)器返回狀態(tài)碼200 OK響應(yīng),響應(yīng)包含最初的請求內(nèi)容(將HTTP請求原樣返回)。
  • CONNECT:要求在于代理服務(wù)器通信時建立隧道,用隧道協(xié)議進行TCP通信。主要使用SSL(Secure Sockets Layer, 安全套接層)和TLS(Transport Layer Security,傳輸層安全)協(xié)議把通信內(nèi)容加密后經(jīng)網(wǎng)絡(luò)隧道傳輸。格式為CONNECT 代理服務(wù)器名:端口號 HTTP版本號

HTTP響應(yīng)

HTTP響應(yīng)同樣可分為Header和Body,它一般長這樣:

HTTP/1.1 200 ok
Date: ...
Server: ..
...
空行(CR + LF)
<html>
...
</html>

第一行是狀態(tài)行,包含HTTP版本、表明響應(yīng)結(jié)果的狀態(tài)碼和原因短語。接下來是一些首部字段,一般包括響應(yīng)首部字段、通用首部字段、實體首部字段和RFC里未定義的首部(Cookie等),最后是報文主體。下面重點說明一下狀態(tài)碼和原因短語,它們描述了本次請求的結(jié)果。

狀態(tài)碼

狀態(tài)碼的第一位數(shù)字指定了響應(yīng)類別,共可分為5類:

  • 1XX:Informational(信息性狀態(tài)碼),表明接受的請求正在處理。
  • 2XX:Success(成功狀態(tài)碼),表明請求正常處理完畢。
  • 3XX:Redirection(重定向狀態(tài)碼),表明需進行附加操作以完成請求。
  • 4XX:Client Error(客戶端錯誤狀態(tài)碼),表明服務(wù)器無法處理請求。
  • 5XX:Server Error(服務(wù)器錯誤狀態(tài)碼),表明服務(wù)器處理請求出錯。

下面列舉幾種常見的錯誤碼和原因短語:

  • 200 OK:請求正常處理。
  • 204 No Content:請求正常處理,但沒有資源可返回。
  • 206 Partial Content: 客戶端進行了范圍請求,服務(wù)器成功執(zhí)行這部分GET請求。
  • 301 Moved Permanently: 永久性重定向,表明該資源已被分配了新的URI。
  • 302 Found: 臨時性重定向,表明該資源暫時被分配了新的URI。
  • 303 See Other:表明請求的資源存在另一個URI,明確要求客戶端采用GET方法重定向請求資源。
  • 400 Bad Request:請求報文中存在語法錯誤,需修改請求內(nèi)容后再次發(fā)送。
  • 401 Unauthorized*:請求需包含通過HTTP認證(BASIC認證、DIGEST認證等)的認證信息,瀏覽器初次接收401響應(yīng)會彈出認證窗口。若之前已進行過一次請求,則表示用戶認證失敗。
  • 403 Forbidden:請求資源的訪問被服務(wù)器拒絕。服務(wù)器端沒有必要給出拒絕的詳細理由,不過也可以在響應(yīng)主體部分對原因進行描述。未獲得文件系統(tǒng)的訪問授權(quán)(比如在IIS上部署網(wǎng)站時默認不能通過瀏覽器訪問文件)、訪問權(quán)限出現(xiàn)問題(比如從未授權(quán)的發(fā)送源IP地址試圖訪問)都有可能返回403響應(yīng)。
  • 404 Not Found:服務(wù)器無法找到請求的資源(也可在服務(wù)器端拒絕訪問且不想說明理由時使用)。
  • 500 Internal Server Error:服務(wù)器端執(zhí)行請求時發(fā)生內(nèi)部錯誤。多為服務(wù)器端程序出現(xiàn)Bug。
  • 503 Service Unavailable:服務(wù)器處于超負載或正在停機維護,暫時無法處理請求。

HTTP協(xié)議的一些特性

HTTP協(xié)議的初始版本中,每進行一次HTTP通信就要斷開一次TCP連接。這在當年都是一些小容量文本傳輸?shù)那闆r下是可行的,但隨著HTTP的普及,傳輸過程中包含大量圖片的情況多了起來。譬如使用瀏覽器瀏覽一個包含多張圖片的HTML頁面時,在發(fā)送請求訪問該HTML頁面資源的同時,也會請求該頁面包含的其他資源如各種不同的圖片,它們是在不同服務(wù)器上的。如果每次請求都得重新建立一次TCP連接的話,無疑會增加通信量的開銷,而且頻繁斷開又重連會導(dǎo)致頁面加載緩慢,影響用戶體驗。

持久連接(HTTP Persistent Connections)

為了解決上述問題,HTTP/1.1和一部分HTTP/1.0開始支持持久連接。持久連接的特點是,只要任意一端沒有明確提出斷開連接,則保持TCP連接狀態(tài)。HTTP/1.1中所有的連接默認都是持久連接。

管線化(pipelining)

持久連接使得多數(shù)請求以管線化方式發(fā)送成為可能。以往發(fā)送請求后需等待并收到響應(yīng)后才能發(fā)送下一個請求,管線化技術(shù)出現(xiàn)后,無需等待亦可發(fā)送下一個請求。這就實現(xiàn)了多個請求的并行發(fā)送,提高了網(wǎng)絡(luò)通信效率。

Cookie

HTTP是無狀態(tài)協(xié)議,它不對之前發(fā)生過的請求和響應(yīng)狀態(tài)進行管理。無狀態(tài)自然可以減少服務(wù)器的CPU及內(nèi)存資源消耗,但有些時候我們又需要對過去的狀態(tài)進行管理,譬如登錄驗證之后用戶在瀏覽該網(wǎng)站其他網(wǎng)頁時應(yīng)該保持登錄的狀態(tài)而不是重新進行登錄。當然要實現(xiàn)狀態(tài)管理,我們可以使用很多方法,無外乎是在服務(wù)器端和客戶端都保存一個憑證,之后每次請求都帶上這個憑證,然后在服務(wù)器端進行比對,獲取狀態(tài)信息。HTTP協(xié)議中引入的Cookie技術(shù),也是為了解決狀態(tài)管理問題,采用的方法也跟我上面說的差不多,只不過這是發(fā)生在協(xié)議層面,不需要自己寫很多代碼管理。

具體來說,Cookie技術(shù)通過在請求和響應(yīng)報文中寫入Cookie信息來控制客戶端狀態(tài),過程如下:

  1. 客戶端第一次發(fā)送請求,請求報文中沒有Cookie信息。
  2. 服務(wù)器端生成Cookie信息,在響應(yīng)報文中通過Set-Cookie這個首部字段,通知客戶端保存Cookie,大概長這樣:

HTTP/1.1 200 ok
...
<Set-Cookie: sid=1345077140226724;path=/;expires=Fri,=>23-Oct-15 07:12:20 GMT>
Content-Type: text/plain; charset=UTF-8

  1. 客戶端再次發(fā)送請求時,自動在請求報文中加入Cookie值后發(fā)送出去。大概長這樣:

GET /image/ HTTP/1.1
Host: github.com
Cookie: sid=1345077140226724

  1. 服務(wù)器端收到Cookie信息后,會去檢查從哪個客戶端發(fā)來的連接請求,然后對比服務(wù)器上的記錄,得到之前的狀態(tài)信息。

HTTP協(xié)議并不算很復(fù)雜,不過涉及的內(nèi)容也不少。總之,今天先這樣吧。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

推薦閱讀更多精彩內(nèi)容