深刻理解網絡協議之HTTP

超文本傳輸協議(HyperText Transfer Protocol), 是一種用於分佈式、協做式和超媒體信息系統的應用層協議, 是萬維網的數據通訊的基礎(維基百科)。這裏咱們主要關注一下什麼是應用層,以及網絡是如何分層的.html


網絡的分層

網絡爲何要分層[1]?web

  1. 各層之間相互獨立, 某一層並不須要知道它下一層是如何實現的,而僅僅須要知道該層經過層間的接口所提供的服務。因爲每一層只實現一種相對獨立的功能,於是能夠將一個難以處理的複雜問題分解爲若干個較容易處理的更小問題,這樣,整個問題的複雜度就降低了。
  2. 靈活性, 當任何一層發生變化時,只要層間接口關係保持不變,則在這層以上或如下各層均不受影響,此外,對某一層提供的服務還能夠進行修改。當某層提供的服務再也不須要時,甚至能夠將這層取消
  3. 結構上可分割開。各層均可以採用最合適的技術來實現。
  4. 易於實現和維護。這種結構使得實現和調試一個龐大而又複雜的系統變得易於處理,由於整個系統已被分解爲若干個相對獨立的子系統。
  5. 能促進標準化工做。由於每一層的功能及其所提供的服務都已有了精確的說明。

OSI七層模型

開放式系統互聯通訊參考模型,由國際標準化組織提出。
OSI將網絡分爲七層: 應用層、表示層、會話層、傳輸層、網絡層、鏈路層、物理層。算法

TCP/IP五層模型

TCP/IP是實際的標準, 分爲五層: 應用層、傳輸層、網絡層、鏈路層、物理層。瀏覽器

TCP/IPOSI的分層的對應關係, 以下圖所示:
緩存

TCP/IP與OSI

TCP/IP也能夠說是四層, 若是是四層的話就是把鏈路層物理層統稱爲網絡接口層安全


HTTP的過程

讓咱們從一次請求過程來了解HTTPbash

請求的準備

  1. 在輸入URL以後,首先須要DNS來將域名解析爲IP地址。
  2. 創建TCP鏈接(三次握手),創建鏈接的時候是須要發送IP包的。
  3. 若是是HTTPS會進行TLS/SSL的握手。

請求的構建

鏈接創建之後,就是要向服務器發送請求,那麼請求格式是怎麼樣的呢? HTTP1.1爲明文傳輸,因此咱們很容易可以在ChromeNetwork中看到,請求的格式以下圖所示:
服務器

HTTP請求格式

從上圖能夠看出,請求分爲了三部分:請求行,首部,實體。websocket

首部與實體之間使用空行分隔。網絡

請求行

請求行由三部分構成:方法,URLHTTP版本號,以空格隔開。

方法

主要的方法有:GET POST OPTIONS HEAD

GET

若是有參數,會將其放在URL中: 優勢:

  1. 請求的URL能夠被緩存
  2. 能夠手動輸入,並保存參數
  3. 相對較快(會在TCP第三次握手時將報文隨握手包發送)。 缺點:
  4. 參數有大小限制(受限於URL的長度)
  5. 參數可見,相對不安全

GET請求的過程[2]:

  1. 瀏覽器請求TCP鏈接(第一次握手)
  2. 服務器答應進行TCP鏈接(第二次握手)
  3. 瀏覽器確認,併發送GET請求頭和數據
  4. 服務器返回200 OK響應
POST

參數存在於實體中: 優勢:

  1. 能發送更多的數據。
  2. 參數不直接可見,相對安全(相對GET,抓包除外)。 缺點:
  3. 相對較慢(在首部中相對GET多了幾個用於協商的首部,且須要待第三次握手後再發送報文)。

POST請求的過程[2]:

  1. 瀏覽器請求TCP鏈接(第一次握手)
  2. 服務器答應進行TCP鏈接(第二次握手)
  3. 瀏覽器確認,併發送POST請求頭(第三次握手)
  4. 服務器返回100 Continue響應
  5. 瀏覽器發送數據
  6. 服務器返回200 OK響應
OPTIONS

CORS 中預檢請求

HEAD

請求資源的首部信息, 而且這些首部與GET方法請求時返回的一致。響應不該包含響應實體,即便包含了實體也必須忽略掉。

URL

URL(Uniform Resource Locator), 統一資源定位符, 是因特網上標準的資源的地址。

完整格式:協議類型:[//[訪問資源須要的憑證信息@]服務器地址[:端口號]][/資源層級UNIX文件路徑]文件名[?查詢][#片斷ID]

另外,與URL相關的定義還有URIURNURI(Uniform Resource Identifier),統一資源標識符,用於標識某一互聯網資源名稱的字符串。 URN(Uniform Resource Name),統一資源名稱,一種爲資源提供持久的、位置無關的標識方式。

URLURNURI的子集,三者關係,以下圖所示:

URL, URN, URI

舉個栗子:urn:isbn:0-486-27557-4這是一個資源,它是URN,也是URI,但不是URL

HTTP 版本

主要版本:0.九、1.0、1.12

首部

首部是key: value形式,經過冒號空格分隔,爲客戶端和服務器分別處理請求和相應提供所須要的信息。 首部分爲四類:請求首部,響應首部,通用首部,實體首部。

請求首部

顧名思義,只會在請求報文中存在。

  1. Accept-Charset:客戶端支持的字符集,例:utf-8
  2. Accept-Encoding:客戶端能夠接受的內容編碼形式,例:gzip
  3. Referer:對請求中URL的原始獲取方。
  4. Host:請求資源所在服務器。
  5. ......

通用首部

  1. Accept-Language:提示用戶指望得到的天然語言的優先順序。
  2. User-Agent:用來識別發送請求的瀏覽器。
  3. Cache-Control:緩存控制。
  4. ......

實體首部

  1. Content-Encoding:實體的編碼方式。
  2. Content-Language:實體的天然語言。
  3. Content-Type:實體的媒體類型。
  4. ......

響應首部

  1. Location:令客戶端重定向至指定URL
  2. Retry-After:對再次發起請求的時機要求。
  3. ServerHTTP服務器的安裝信息。
  4. ETag:資源匹配信息(緩存相關)。
  5. ......

一切準備完成後就是發送請求。

請求的發送與接收

請求發送接收的過程以下圖所示:

請求的發送

請求的發送

  1. 瀏覽器將HTTP構建完成後,經過網絡線程將請求報文交給TCP
  2. TCP將請求的報文進行分割,並將各個報文包入TCP的頭部,交給IP
  3. IPTCP報文包入IP的頭部,交個鏈路層。
  4. 鏈路層報上以太網首部經過物理層發送報文(待後續補充)。

請求的接收

  1. 網卡接收到請求後,會先查看目標MAC地址是否爲本身的MAC地址,若是是會把以太網頭部去除,交個上層協議。
  2. IP收到鏈路層發送的數據後,會檢查目標IP是否爲本身的IP,若是是把IP頭部去除,交給上層協議。
  3. TCP收到數據後,去掉TCP頭部,交給瀏覽器。

請求的響應

響應的構建

響應的格式

響應與請求除了狀態行外結構基本相同,一樣分爲 3 部分:狀態行,首部,實體。

狀態行

狀態行分爲 3 部分:HTTP版本,狀態碼,短語,以空格分隔,其中短語爲對狀態碼的解釋。

狀態碼

狀態碼分類

主要狀態碼介紹
  1. 200 OK:表示從客戶端發送來的請求在服務器端被正常處理了。對應請求資源的實體主體隨報文首部做爲響應返回(HEAD 方法不會返回實體,即便返回也會被忽略)。
  2. 204 Not Content:服務器接收的請求已成功處理,可是再返回的響應報文中不包含實體的主體部分。另外,也不容許返回任何實體的主體。(MDN:使用慣例是,在PUT 請求中進行資源更新,可是不須要改變當前展現給用戶的頁面,那麼返回204 No Content。例如:提交表單後,不進行頁面跳轉)。
  3. 206 Partial Content:客戶端進行了範圍請求,而服務器成功執行了這部分的GET請求。響應報文中包含由Content-Range指定範圍的的實體內容。
  4. 301 Moved Permanently:永久重定向,表示請求的資源已被分配了新的URL,之後請使用資源如今所指的URL。搜索引擎會根據該響應修正。
  5. 302 Found:臨時重定向,表示請求的資源已被分配了新的URL,但願用戶(本次)能使用新的URL訪問。已改變,且未來還有可能發生改變。
  6. 303 See Other:請求對應的資源存在着另外一個URL,應使用GET方法定向獲取請求的資源。(301302303響應狀態碼返回時幾乎全部的瀏覽器都會把POST改爲 GET,並刪除請求報文的主體,以後請求會自動再次發送。)。
  7. 304 Not Modified:服務器端資源未改變,可直接使用客戶端未過時的緩存,返回結果不包含任何響應的主體部分。
  8. 307 Temporary Redirect:臨時重定向。與302之間的惟一區別在於,當發送重定向請求的時候,307狀態碼能夠確保請求方法和消息主體不會發生變化。
  9. 400 Bad Request:請求報文中存在語法錯誤。當錯誤發生時,需修改請求的內容後再次發送請求。另外,瀏覽器會像200 OK同樣對待該狀態碼。
  10. 401 Unauthorized:表示因爲缺少目標資源要求的身份驗證憑證,發送的請求未獲得知足。這個狀態碼會與WWW-Authenticate首部一塊兒發送,其中包含有如何進行驗證的信息。
  11. 403 Forbidden:表示服務器端有能力處理該請求,可是拒絕受權訪問(無權限)。
  12. 404 Not Found:表示服務器上沒法找到請求的資源。
  13. 500 Internal Server Error:表示服務器端在執行請求時發生了錯誤,也有多是 Web 應用存在的 Bug 或某些臨時的故障。
  14. 503 Service Unavailable:表示服務器暫時處於超負載或正在進行停機維護,如今沒法處理請求。若是事先得知解除以上情況須要的時間,最好寫入Retry-After首部字段再返回給客戶端。

在完成了響應的構建以後,會按照與發送相同的方式將響應發送給客戶端。最後TCP四次回收斷開鏈接。

整個請求過程以下圖所示:

HTTP請求過程


HTTP版本

HTTP/0.9 單行協議

HTTP/0.9很是簡單,請求僅由單行構成,以惟一可用方法GET開頭,其後跟目標資源的路徑。

GET /index.html

響應也很是簡單僅包含響應文檔自己,若是出現錯誤會將錯誤信息以文檔形式返回。

HTTP/1.0 構建可擴展性

主要引入了頭部,及狀態碼,並支持多種文件格式。

HTTP/1.1 標準化的協議

HTTP/1.1 相對 1.0 的不一樣:

  1. 持久鏈接:默認都開啓了Keep-Alive,全部鏈接都被保持,除非在請求頭或響應頭中指明要關閉:Connection: CloseKeep-Alive不會永久保持鏈接,它有一個保持時間,能夠在不一樣的服務器軟件中設定這個時間(實際是在1.0版本引入,但並不會默認開啓)。
  2. 管線化:無需等待上次請求返回也可直接發送下一個請求(實際使用受限,瀏覽器默認不開啓)。
  3. 緩存:增長了新的緩存控制首部,如:Cache-Control等。
  4. Host:請求頭指明瞭服務器的域名(對於虛擬主機來講),以及(可選的)服務器監聽的TCP端口號。
  5. 內容協商機制: 包括語言,編碼,類型等,並容許客戶端和服務器之間約定以最合適的內容進行交換。

HTTP/2 爲了更優異的表現

HTTP/1.1的區別:

  1. 二進制協議:在不改變方法,首部的基礎上,轉換爲二進制協議,稱爲二進制分幀層。
  2. 多路複用:即在一個TCP鏈接中能夠同時發送多個請求。
  3. 流控制:是一種阻止發送方向接收方發送大量數據的機制,以避免超出後者的需求或處理能力:發送方可能很是繁忙、處於較高的負載之下,也可能僅僅但願爲特定數據流分配固定量的資源。
  4. 服務端推送:服務端推送,服務器能夠對一個客戶端請求發送多個響應。
  5. 頭部壓縮。

緩存控制

瀏覽器在首次對資源進行請求時,會記錄緩存相關的首部,在後續請求中根據記錄的首部進行相應的資源讀取操做,如讀取緩存,資源驗證等。 緩存的做用:減小請求次數,減小帶寬;增長加載速度,減小白屏時間。

在說明緩存控制原理以前,先了解下緩存相關的首部。

緩存相關首部

Cache-Control

控制緩存的有效時間,及緩存行爲。
主要值:

  1. max-age:緩存有效時間,即從相應時間後多長時間緩存過時。
  2. no-cache:不緩存,並不是不對資源進行緩存,而是每次請求都須要向源資源服務器驗證資源。
  3. no-store:禁止緩存,禁止瀏覽器對資源進行緩存,每次請求都要從新請求資源。
  4. public:容許全部用戶緩存,包括瀏覽器,代理服務器等。
  5. private:僅容許單個用戶緩存,不容許代理服務器緩存。
  6. ......

對於 Cache-Control: no-cache, max-age=900 這種狀況,no-cache 與 max-age 的優先級與前後順序有關。

Expires

HTTP/1.0提出,表示緩存過時時間,超過這個時間即緩存過時。若是響應中有max-ages-maxage會被覆蓋。

expires: Sun, 02 Sep 2018 14:36:18 GMT

Last-modified

資源的最後修改時間,主要用於在服務器驗證緩存是否被修改時使用。

last-modified: Fri, 18 May 2018 01:10:24 GMT

ETag

資源實體標識,由服務器分配,資源更新時ETge隨之改變,分爲ETagETag。 **弱ETag**很容易生成,但不利於比較。**強ETag**是比較的理想選擇,但很難有效地生成。

ETag: W/"5a323f72-152"(弱) ETag: "33a64df551425fcc55e4d42a148795d9f25f89d4"(強)

緩存請求過程

  1. 判斷該資源是否有緩存。
  2. 若有緩存,判斷緩存是否過時,若是緩存沒過時,直接讀取緩存,狀態碼200 (from memory/disk cache)
  3. 若是緩存過時,判斷是否有ETagLast-Modified,若是存在,則在請求首部中發送對應的首部If-None-MatchIf-Modified-Since,若是沒有則不發送這兩個首部。
  4. 服務器端接收到請求後,判斷根據If-None-MatchIf-Modified-Since來比較資源的ETag若是改變了比較Last-Modified,若是匹配則返回304,若是不匹配,將資源隨實體返回,狀態碼200

from memory cache 與 from disk cache 爲 Chrome 的緩存優化機制,但對於該採用什麼方式,並無找到明確答案。

強緩存與協商緩存

強緩存:不會向服務器發送請求,直接讀取緩存的方式,在上述過程當中直接返回狀態碼200 (from memory/disk cache)。 協商緩存:請求資源時會向服務器發送If-None-MatchIf-Modified-Since(若是存在ETagLast-Modified),服務器驗證後,返回304200

HTTPS

在學習HTTPS以前,咱們瞭解下HTTP的缺點:

  1. 明文通訊(不加密),不安全。
  2. 不驗證通訊方身份,可能遭遇假裝。
  3. 沒法保證報文的完整性,可能在途中遭到了篡改。

HTTPS解決了上述缺點(HTTPS並不是新協議,而是HTTP + TLS

對稱加密

發送端和接收端使用相同的密鑰。發送端使用密鑰加密明文,接收端接收後使用密鑰解析加密信息,獲得明文。
對稱加密最大的問題就是在一對多的時候的密鑰傳輸問題,因此爲了保證安全對稱加密的密鑰是絕對不能公開的。

非對稱加密

非對稱加密有兩個密鑰,一個是公鑰,一個是私鑰,公鑰加密後的密文只能使用私鑰解密,私鑰加密後的密文只能使用公鑰解密。那麼只須要對外展現公鑰就能夠了。
可是,非對稱加密的解密過程速度較慢(對稱加密主要是位運算,而非對稱加密包含了不少乘法或大數模)。

混合加密

充分利用對稱及非對稱加密的優點,使用非對稱加密的方式傳輸對稱加密的密鑰,即有非對稱加密的安全又有對稱加密的速度。 HTTPS(或者說TLS)就是採用了這種方式。

證書與CA

在拿到公鑰後,能不能就直接肯定這個公鑰是值得信任的?答案是確定不能,若是公鑰是某個黑客僞造的,他就能夠修改從發送端接到的請求,在發給服務器了。因此,在拿到公鑰後,首先要驗證公鑰是否是能夠信任的,那麼誰能保證公鑰是能夠信任的,那就必需要是一個你信任的機構,這個機構就是CA,而每一個站點的公鑰實際都是由CA簽發的。因此CA能夠驗證公鑰是否屬於這個站點的。

簽發及驗證過程

  1. 服務器將公鑰交給CA
  2. CA使用本身的私鑰向服務器的公鑰部署數字簽名,並頒發公鑰證書
  3. 客戶端在接收到公鑰證書後,客戶端使用本身信任的CA的公鑰(存在於客戶端證書信任列表中)去驗證簽名是否與公鑰匹配。
  4. 若匹配則認爲公鑰是能夠信任的。

鏈接過程

  1. TCP三次握手後,客戶端發送請求安全鏈接(Client Hello),報文中包含一個隨機字符串,並列出客戶端支持的加密套件,用於協商對稱加密的加密方式。
  2. 服務器端回覆(Server Hello),報文中包含服務端選擇的加密方式;同時將證書和公鑰發送給客戶端,同時報文中包含一個隨機字符串;最後發送完成握手協商結束(Server Hello Done)。
  3. 客戶端接收到證書後,根據證書上的CA,使用該CA的公鑰解密證書,來驗證公鑰是否安全,若是CA的證書由上級CA提供且不在信任列表內,則須要一直向上找到客戶端信任的CA爲止。
  4. 驗證公鑰安全後,客戶端會使用公鑰加密併發送一段叫作Pre-master secret的隨機字符串,客戶端及服務器端使用上面提到的三個隨機字符串,並使用協商好的加密算法計算出對稱加密的密鑰。
  5. 客戶端發送Change Cipher Spec報文,以提示服務器後續通訊將採用計算好的對稱加密密鑰進行通訊
  6. 客戶端繼續發送Finished報文,報文中包含鏈接至今所有報文的總體校驗值,若是服務器端可以正確解密該報文,則握手成功
  7. 服務器端發送Change Cipher Spec報文
  8. 服務器端發送Finished報文,鏈接創建。

WebSocket

WebSocket是能夠實現客戶端與服務器端雙向通訊的新協議,除了藉助HTTP完成一次握手外,與HTTP沒有關係。

鏈接過程

  1. TCP三次握手。
  2. 客戶端發送升級請求,請求首部以下:
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==
Sec-WebSocket-Protocol: chat, superchat
Sec-WebSocket-Version: 13
複製代碼

上述首部中主要是用到了Upgrade首部,用於通知服務器切換協議到WebSocket。 3. 服務器端接收到升級協議的請求後,若是支持WebSocket會響應該請求。

HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: HSmrc0sMlYUkAGmm5OPpG2HaGWk=
Sec-WebSocket-Protocol: chat
複製代碼

響應狀態碼:101,表示服務器端應客戶端升級協議的請求正在升級協議。 4. WebSocket握手完成,後續通訊將使用WebSocket協議。

參考:
[1]《計算機網絡(第五版)》(謝希仁)
[2] http GET 和 POST 請求的優缺點、區別以及誤區
[3] TLS 握手優化詳解

相關文章
相關標籤/搜索