面試官常問的HTTP知識點
網際網路中的資料是通過資料包來傳輸的,IP
通過DNS
查詢IP地址
進而把資料包送達目的主機,UDP
接過資料包,通過埠號把資料包送往具體的應用,而使用TCP
可保證資料的完整性
當傳輸層TCP/IP
協議將資料傳輸到網路上時,瀏覽器可通過HTTP
協議進行文字傳輸,物聯網可通過MQTT
協議進行互動
一、UDP
UDP
傳輸非常快,適合線上影片、互動遊戲這類強互動的場景
對於資料可靠性有要求的場景則不太適合,它有個大缺點:不能保證資料可靠性
- 不提供重發機制,直接丟棄當前的包
- 傳送之後不售後,無法確認是否到達目的地
- 無法還原資料包成完整的檔案
但它的兄弟TCP
可以代勞
二、TCP
TCP
是一種面向連線的、可靠的、基於位元組流的傳輸層通訊協議。解決了丟失資料包的問題,並且提供了組裝資料包的能力。這不得不感謝傳送端不僅給它提供了源埠號和目標埠號,還提供了序列號,引入了資料包排列機制
1、連線過程
1.1、建立連線
TCP
是面向連線的,在資料通訊之前就做好兩端的準備工作,在客戶端和服務端通過三個資料包來確認連線的建立
- 一開始,客戶端和服務端都處於
close
狀態,接著服務端主動監聽某個埠,處於listen
狀態 - 客戶端生成初始序列號
client_isn
置於TCP
首部的序列號中,同時更改SYN
標誌為1
向伺服器發起連線,之後處於SYN-SENT
狀態 - 服務端收到
SYN
報文同樣生成初始序列號server_isn
置於TCP
首部的序列號中,並將客戶端序列號+1
置於TCP
首部的確認應答號中,同時更改SYN
和ACK
標誌為1
,傳送SYN + ACK
報文並更改狀態為SYN_RCVD
- 客戶端收到
SYN + ACK
報文,將服務端序列號+1
填入確認應答號並回復ACK
應答報文變更狀態為established
- 伺服器收到應答後也進入
established
狀態
只有第三次握手可以攜帶資料,前面兩次是不可攜帶資料的
1.2、為什麼三次握手?
- 通過三次握手能防止歷史連線的建立,能減少雙方不必要的資源開銷,能幫助雙方同步初始化序列號
- 兩次握手無法仿製歷史連線的建立,會造成雙方資源的浪費,也無法可靠的同步雙方序列號
- 四次握手:三次握手就已經理論上最少可靠連線建立,因此不需要使用更多的通訊次數
2、傳輸資料
TCP
是可靠的,接收端必須對每個資料包進行確認操作,即重發機制
當傳送端傳送了一個數據包之後,在規定時間內沒有接收到反饋的確認資訊,則判斷資料包丟失,觸發重發機制
TCP
是基於位元組流的,接收端可通過TCP
提供的序號進行排序,進而保證資料的完整性,即排列機制
3、斷開過程
3.1、斷開連線
- 客戶端主動關閉連線,傳送
FIN
報文,即更改FIN
標誌為1
同時進入FIN_WAIT_1
狀態 - 服務端收到報文後發出
ACK
應答報文,接著進入CLOSED_WAIT
狀態 - 客戶端收到報文後,進入
FIN_WAIT_2
狀態 - 伺服器處理完成後發出
FIN
報文,並進入LAST_ACK
狀態 - 客戶端收到報文後發出
ACK
應答報文,接著進入TIME_WAIT
狀態 - 伺服器收到
ACK
應答報文後完成連線關閉 - 客戶端 等待兩倍報文最大生存時間(MSL)後 自動進入
close
狀態,完成連線關閉
主動關閉連線的,才有
TIME_WAIT
狀態
3.2、為什麼四次揮手?
- 關閉連線時,客戶端向服務端傳送
FIN
時,僅代表客戶端不再發送資料但能接收資料 - 服務端接收到
FIN
時,回覆一個ACK
,僅代表收到報文,但伺服器可能還有資料需要處理和傳送,確保不再發送資料時才傳送FIN
給到客戶端表示同意現在關閉連線
三、HTTP
HTTP
協議以 ASCII
碼傳輸,構建於 TCP/IP
協議之上的應用層協議,預設埠號是 80
,它是無連線無狀態的超文字傳輸協議
1、HTTP 報文
1.1、請求報文
規範把 HTTP
請求分為三個部分:請求行、請求頭 和 訊息主體
[method] [url] [version]
[headers]
[body]
HTTP
中的GET
、POST
、PUT
、DELETE
對應著資源的查、增、改、刪4個操作
1.1.1、GET
只讀操作,是安全且冪等的
- 安全:請求方法不會破壞伺服器上的資源
- 冪等:多次執行相同的操作,結果都是相同的
1.1.2、POST
讀寫操作,是不安全且不冪等的
1.1.3、PUT
不同於POST
,PUT
是冪等的
1.1.4、OPTIONS
用以從伺服器獲取更多資訊
1.2、響應報文
同樣HTTP
響應分為三個部分:狀態行、響應頭 和 響應正文
[version] [status code] [status msg]
[headers]
[body]
- 常見的狀態碼有
狀態碼 | 狀態描述 | 備註 |
---|---|---|
206 | Partial Content | 範圍響應,主體包含所請求的資料區間<br/>斷點續傳時通過 Range 指定區間 |
301 | Moved Permanently | 請求永久重定向 |
302 | Moved Temporarily | 請求臨時重定向 |
304 | Not Modified | 未修改,使用快取檔案(協商快取) |
400 | Bad Request | 客戶端請求有語法錯誤 |
401 | Unauthorized | 請求未經授權(同WWW-Authenticate 一起使用)<br/>在後續請求中攜帶 Authorization 用於驗證使用者代理身份的憑證 |
403 | Forbidden | 伺服器拒絕提供服務,通常在響應正文給出原因 |
404 | Not Found | 請求資源不存在 |
500 | Internal Server Error | 伺服器發生不可預期的錯誤 |
503 | Service Unavailable | 伺服器當前無法處理請求,需等待伺服器恢復正常 |
2、HTTP 演變
版本 | 核心訴求 | 新增特性 |
---|---|---|
HTTP/1.0 | 支援多種型別的檔案下載 | 引入請求頭、響應頭、狀態碼 |
HTTP/1.1 | 提高對頻寬的利用率 | 1、持久連線(每個域名最多同時維護 6 個 TCP 持久連線) 2、使用 CDN 實現域名分片機制 3、提供虛擬主機的支援(Host 欄位) 4、增加快取策略 5、安全機制(CORS) |
HTTP/2.0 | 提升網路速度 | 1、多路複用 2、設定請求的優先順序 3、伺服器推送 4、頭部壓縮 5、二進位制格式 |
HTTP/3.0 | 構建高效網路 | 1、甩掉TCP、TLS 的包袱,使用UDP協議 2、QUIC協議 |
HTTPS | 構建安全HTTP | 引入SSL 、混合加密、摘要演算法 、數字證書 |
2.1、持久連線
HTTP/1.1
中增加了持久連線的方法,即在一個 TCP
連線上可以傳輸多個 HTTP
請求,只要瀏覽器或者伺服器沒有明確斷開連線,那麼該 TCP
連線會一直保持,提升了整體 HTTP
的請求時長。目前瀏覽器中對於同一個域名,預設允許同時建立 6 個 TCP 持久連線
Connection: Keep-Alive; // HTTP/1.1預設使用持久連線,如需關閉,請求頭Connection設定為close
Keep-Alive: timeout=5, max=100; // HTTP 長連線不可能一直保持,timeout=5 表示這個TCP通道可以保持5秒,max=100,表示這個長連線最多接收100次請求就斷開
2.2、使用 CDN 實現域名分片機制
2.3、提供虛擬主機的支援
Host
表示當前的域名地址,伺服器可以根據不同的 Host
值做不同的處理
Host: <host>:<port>; // host: 伺服器的域名(用於虛擬主機) port: 伺服器監聽的 TCP 埠號
2.4、快取策略
2.5、安全機制
2.5.1、會話跟蹤
HTTP
是無狀態協議,即瀏覽器對於事務的處理沒有記憶能力,可通過Cookie
和JWT
機制來進行會話跟蹤
Cookie
機制
服務端第一次收到請求時建立session
物件生成對應的sessionID
,將其放進Set-Cookie
傳送給客戶端,下一次訪問時,客戶端攜帶sessionID
請求服務端,服務端可通過sessionID
識別使用者資訊
Cookie
的過期時間、域、路徑、有效期、適用站點都可以根據需要來指定
功能 | 屬性 | 例子 | 補充說明 |
---|---|---|---|
定義 Cookie 的生命週期 | Expires <br/> Max-Age | Set-Cookie: key=value; Expires=Wed, 21 Oct 2022 07:28:00 GMT | 設定的日期和時間只與客戶端相關,會話期 Cookie 僅在會話期內有效 |
限制訪問 Cookie | HttpOnly<br/>Secure | Set-Cookie: key=value; Secure; HttpOnly | HttpOnly:僅作用於伺服器<br/>Secure僅適用於 HTTPS 協議加密過的請求 |
Cookie 的作用域 | Domain<br/>Path | Set-Cookie:Domain=mozilla.org;Path=/docs | Domain 指定了哪些主機可以接受 Cookie<br/>Path 指定了主機下的哪些路徑可以接受 Cookie |
SameSite | None<br/>Strict<br/>Lax | Set-Cookie: key=value; SameSite=Strict | None:瀏覽器會在同站請求、跨站請求下繼續傳送 cookies(舊版本瀏覽器預設選項)<br/>Strict:瀏覽器將只在訪問相同站點時傳送 cookie<br/>Lax:與 Strict 類似,但使用者從外部站點導航至URL時除外(新版本瀏覽器預設選項) |
JWT
機制 (JSON Web Token)
Cookies
只適用於單節點的域 或 節點的子域,若通過第三個節點訪問會被禁止。而JWT
機制則支援跨域認證,可通過多個節點進行使用者認證
服務端第一次收到請求時,進行認證後生成一個 Token
(簽名後的JSON
物件)傳送給客戶端。客戶端可將收到的jwt
儲存在Cookie
或localStorage
上,之後每次與服務端通訊都攜帶上,可通過Cookie
自動傳送,但這種方式不能跨域,比較推薦通過 POST
請求的資料體 或 Authorization
進行傳遞
注意喔,JWT 的 Cookie 資訊儲存在客戶端,即服務端是無狀態的
2.5.2、跨源資源共享(CORS)
規範要求那些可能產生副作用的請求,瀏覽器必須首先使用OPTIONS
方法發起一個預檢請求,從而獲知服務端是否允許跨域請求。伺服器確認允許後才發起實際的HTTP
請求。在預檢請求的返回中,服務端可通知客戶端是否需要攜帶身份憑證
- 簡單請求
若請求滿足下述所有條件,則稱之為簡單請求,它不會觸發預檢請求
1、使用GET
、HEAD
和POST
請求方法 2、Content-Type
的值僅限於text/plain
、multipart/form-data
和application/x-www-form-urlencoded
3、請求中沒有註冊任何事件監聽器,沒有使用 ReadableStream
物件
// 附帶身份憑證的簡單請求
withCredentials:true; // 向伺服器傳送 Cookies
Access-Control-Allow-Credentials: true; // 服務端允許附帶身份憑證
- 複雜請求
響應頭 | 例子 | 說明 |
---|---|---|
Access-Control-Allow-Origin |
Access-Control-Allow-Origin: <origin>/* Vary: Origin |
origin:指定允許訪問該資源的URI<br/>若指定了具體的域名,則Vary 的值必須包含Origin ,表明服務端按URI返回對應內容 |
Access-Control-Expose-Headers |
Access-Control-Expose-Headers: X-My-Custom-Header |
伺服器把允許瀏覽器訪問的頭放入白名單 |
Access-Control-Allow-Credentials |
Access-Control-Allow-Credentials: true |
指定了credentials:true 時是否允許瀏覽器讀取 response 的內容<br/>在預檢請求的響應時,指定實際的請求是否可以使用 credentials |
Access-Control-Max-Age |
Access-Control-Max-Age: 86400 |
預檢請求的結果在多少秒內有效 |
Access-Control-Allow-Methods |
Access-Control-Allow-Methods: <method>[, <method>]* |
預檢請求的響應,指明瞭實際請求所允許使用的 HTTP 方法 |
Access-Control-Allow-Headers |
Access-Control-Allow-Headers: <field-name>[, <field-name>]* |
預檢請求的響應,指明瞭實際請求中允許攜帶的首部欄位 |
2.6、支援動態生成內容
伺服器會將資料分割成若干個任意大小的資料塊,每個資料塊傳送時會附上上個數據塊的長度,最後使用一個零長度的塊作為傳送資料完成的標誌,因此對於下載請求來說,是沒有辦法實現進度的
Transfer-Encoding: gzip, chunked; // 分塊:chunked 壓縮演算法:compress、deflate、gzip
2.7、多路複用
一個域名只使用一個TCP
長連線來傳輸資料,這樣整個頁面資源的下載過程只需要一次慢啟動,避免了多個 TCP
連線競爭頻寬的問題。移除了序列請求,順應的解決了隊頭阻塞問題
2.8、設定請求的優先順序
每個資料流都標記著獨一無二的編號,客戶端可以指定資料流的優先順序
2.9、伺服器推送
服務端主動向客戶端傳送訊息,即:當用戶請求一個 HTML
頁面之後,伺服器知道該 HTML
頁面會引用幾個重要的 JavaScript
檔案和 CSS
檔案,那麼在接收到 HTML
請求之後,附帶將要使用的 CSS
檔案和 JavaScript
檔案一併傳送給瀏覽器,這樣當瀏覽器解析完 HTML
檔案之後,就能直接拿到需要的 CSS
檔案和 JavaScript
檔案,大大提升了頁面首次渲染速度
2.10、頭部壓縮
HTTP/2.0
引入HPACK
演算法:在客戶端和伺服器同時維護一張頭資訊表,所有欄位都會存入這個表生成一個索引號,相同欄位只發送對應的索引號,即:同時發出多個請求,請求頭一樣或相似,則協議會將重複部分消除
2.11、二進位制格式
HTTP/2.0
全面採用二進位制格式,頭資訊和資料體都是二進位制,統稱為「幀」提高了資料傳輸的效率
2.12、QUIC協議
- 實現了類似
TCP
的流量控制、傳輸可靠性的功能 - 集成了
TLS
加密功能,減少了握手所花費的RTT
個數 - 實現了
HTTP/2
中的多路複用功能
不同於 TCP,QUIC 實現了在同一物理連線上可以有多個獨立的邏輯資料流,實現了資料流的單獨傳輸,避免了 TCP 中隊頭阻塞的問題
- 實現了快速握手功能,基於
UDP
的QUIC
可使用0-RTT
|1-RTT
來建立連線
3、HTTPS
HTTPS
在HTTP
和TCP
之間加了一層用於加解密的SSL/TLS
協議,通過資訊加密、校驗機制 和 身份證書 保證通訊的安全性
- 客戶端 傳送 對稱加密套件列表、非對稱加密套件列表 和 客戶端隨機數 給到服務端
- 服務端 儲存 客戶端隨機數 和 私鑰,回覆 選中的對稱加密套件、非對稱加密套件 和 服務端隨機數 以及 數字證書
- 客戶端向
CA
機構驗證數字證書,證實服務端身份並獲取公鑰 - 客戶端利用兩端的隨機數計算出
pre-master
,並用獲取到的公鑰進行加密,傳送加密後的pre-master
- 服務端拿出私鑰進行解密,得到
pre-master
- 服務端和客戶端使用這三組隨機數生成會話金鑰,並返回確認訊息
- 之後使用對稱加密進行通訊
3.1、混合加密
HTTPS
通過非對稱加密交換「會話金鑰」後續通訊使用對稱加密,這是由於
- 非對稱加密使用兩個金鑰:公鑰和私鑰,公鑰可儲存在
CA
機構同時儲存私鑰。可以安全的進行金鑰交換,但速度慢 - 對稱加密只使用一個金鑰,無法做到安全的金鑰交換,但速度快
3.2、摘要演算法
摘要演算法通過生成唯一的指紋,用於校驗資料的完整性。客戶端在進行通訊前會通過摘要演算法得出明文的指紋,請求時將指紋和明文一併加密,服務端收到密文後進行解密,比對攜帶的指紋和當前計算的指紋是否一致,一致則說明資料完整
3.3、數字證書
權威機構CA
簽發認證的數字證書【包含了公鑰、組織資訊、CA資訊、有效時間、證書序列號、CA生成的數字簽名等】這些資訊是明文的,同時可向瀏覽器證明伺服器的身份
四、MQTT
MQTT
是基於二進位制訊息的釋出/訂閱程式設計模式的訊息協議,非常適合需要低功耗和網路頻寬有限的IoT場景
- 裝置連線
裝置通過MQTT
協議連線到物聯網雲服務,進而可以進行裝置管理及資料管理
- 訊息型別
MQTT
擁有14
種不同的訊息型別,比如CONNECT
表示客戶端連線到MQTT代理,CONNACK
表示連線確認
- 主題
MQTT
提供了主題對訊息進行分類,訊息是一個UTF-8
的字串,通過類似正則的規則進行匹配分類,比如:+
可以過濾一個層級,*
可以過濾任意級別的層級(必須在主題最後)
- 服務質量
MQTT
提供級別0
、級別1
和級別2
三種服務質量
服務質量 | 訊息可靠性 | 解釋 |
---|---|---|
級別0 | 盡力而為 | 不提供重發 |
級別1 | 至少一次 | 提供重發,併發可能造成重複訊息 |
級別2 | 恰好一次 | 不丟失不重複,但增加延時減少併發 |