初識 HTTP#
輸入 url -> browser 進程處理輸入信息 -> 瀏覽器內核向伺服器發起請求 -> 瀏覽器內核讀取響應 -> 瀏覽器內核進行渲染 -> browser 進程頁面加載完成
-
Hyper Text Transfer Protocol (HTTP)超文本傳輸協議
-
它是應用層協議,基於傳輸層的 TCP 協議
-
請求、響應
-
簡單可擴展(可以自定義請求頭,只要客戶端伺服器之間可以理解)
-
無狀態
協議分析#
發展歷程#
報文結構#
HTTP/1.1#
如圖,可以看到請求和響應的請求頭、返回的狀態碼、等等
Method | 说明 |
---|---|
GET | 請求一個指定資源的表示形式,使用 GET 的請求應該只用於獲取數據 |
POST | 用於將實體提交到指定的資源,通常導致在伺服器上的狀態變化或副作用 |
PUT | 用請求有效載荷替換目標資源的所有當前表示 |
DELETE | 刪除指定的資源 |
HEAD | 請求一個與 GET 請求的響應相同的響應,但沒有響應體(用的比較少) |
CONNECT | 建立一個到由目標資源標識的伺服器的隧道。(用的比較少) |
OPTIONS | 用於描述目標資源的通信選項。 |
TRACE | 沿著到目標資源的路徑執行一個消息環回測試。(用的比較少) |
PATCH | 用於對資源應用部分修改。 |
-
Safe(安全的):不會修改伺服器數據的方法,如讀數據 GET、HEAD、OPTIONS 等
-
Idempotent(幂等):同樣的請求被執行一次與連續執行多次的效果是一樣的,伺服器的狀態也是一樣的,所有 safe 的方法都是 Idempotent 的 如 GET、HEAD、OPTIONS、PUT、DELETE 等
狀態碼#
- 200 OK - 客戶端請求成功
- 301 - 資源(網頁等)被永久轉移到了其它 URL
- 302 - 臨時跳轉
- 401 - Unauthorized - 請求未經授權
- 404 - 請求資源不存在,可能是輸入了錯誤的 URL
- 500 - 伺服器內部發生了不可預期的錯誤
- 504 Gateway Timeout - 網關或者代理的伺服器無法在規定的時間內獲得想要的響應
RESTful API#
一種 API 設計風格:REST - Representational State Transfer
- 每一個 URI 代表 — 種資源
- 客戶端和伺服器之間,傳遞這種資源的某種表現層
- 客戶端通過 HTTP method,對伺服器端資源進行操作,實現 "表現層狀態轉化"。
請求 | 返回碼 | 含義 |
---|---|---|
GET /zoos | 200 OK | 列出所有動物園,伺服器成功返回了 |
POST /zoos | 201 CREATED | 新建一個動物園,伺服器創建成功 |
PUT /zOos/ID | 400 INVALID REQUEST | 更新某個指定動物園的信息 (提供該動物園的全部信息); 用戶發出的請求有錯誤,伺服器沒有進行新建或修改數據的操作 |
DELETE /zoos/ID | 204 NO CONTENT | 刪除某個動物園,刪除數據成功 |
常用請求頭#
請求頭 | 說明 |
---|---|
Accept | 接收類型,表示瀏覽器支持的 MIME 類型 **(對標伺服器返回的 Content-Type)** |
Content-Type | 客戶端發送出去實體內容的類型 |
Cache-Control | 指定請求和響應遵循的快取機制,如 no-cache |
lf-Modified-Since | 對應伺服器的 Last-Modified,用來匹配看文件是否變動,只能精確到 1s 之內 |
Expires | 快取控制,在這個時間內不會請求,直接使用快取,伺服器時間 |
Max-age | 代表資源在本地快取多少秒,有效時間內不會請求,而是使用快取 |
If-None-Match | 對應伺服器的 ETag,用來 ** 匹配文件內容是否改變 ** (非常精確) |
Cookie | 有 cookie 並且同域訪問時會自動帶上 |
Referer | 該頁面的來源 URL (適用於所有類型的請求,會精確到詳細頁面地址, csrf 攔截常用到這個字段) |
Origin | 最初的請求是從哪裡發起的((只會精確到端口) ,Origin 比 Referer 更尊重隱私 ** |
User-Agent | 用戶客戶端的一些必要信息,如 UA 頭部等 |
常用響應頭#
響應頭 | 說明 |
---|---|
Content-Type | 伺服器返回的實體內容的類型 |
Cache-Control | 指定請求和響應遵循的快取機制,如 no-cache |
Last- Modified | 請求資源的最後修改時間 |
Expires | 應該在什麼時候認為文檔已經過期,從而不再快取它 |
Max-age | 客戶端的本地資源應該快取多少秒,開啟了 Cache-Control 後有效 |
ETag | 資源的特定版本的標識符,Etags 類似於指紋 |
Set-Cookie | 設置和頁面關聯的 cookie, 伺服器通過這個頭部把 cookie 傳給客戶端 |
Server | 伺服器的一些相關信息 |
Access-Control-Allow-Origin | 伺服器端允許的請求 Origin 頭部 (如為 *) |
快取#
強快取
本地有了直接用就好了
- Expires(到期時間),時間戳
- Cache-Control
- 可快取性
- no-cache:協商快取驗證
- no-store:不使用任何快取
- public、private 等
- 到期
- max-age:單位是秒,存儲的最大生存週期,相對於請求的時間
- 重新驗證 * 重新加載
- must-revalidate:一旦資源過期,在成功向原始伺服器驗證之前,不能使用)()
- 可快取性
協商快取
與 Server 端要通信,再確定要不要用它
- Etag/If-None-Match:資源的特定版本的標識符,類似於指紋
- Last-Modified/If-Modified-Since:最後的修改時間。(絕對的)
Cookie#
Set-Cookie - response
Name=value | 各種 cookie 的名稱和值 |
---|---|
Expires=Date | Cookie 的有效期,缺省時 Cookie 僅在瀏覽器關閉之前有效。 |
Path= Path | 限制指定 Cookie 的發送範圍的文件目錄,默認為當前 |
Domain=domain | 限制 cookie 生效的域名,默認為創建 cookie 的服務域名 |
secure | 僅在 HTTPS 安全連接時,才可以發送 Cookie |
HttpOnly | JavaScript 腳本無法獲得 Cookie |
SameSite=[None|Strict|Lax] | None 同站、跨站請求都可發送;Strict 僅在同站發送 ;允許與頂級導航一起發送,並將與第三方網站發起的 GET 請求一起發送 |
發展#
HTTP/2 概述:更快、更穩定、更簡單
-
幀 (frame)
-
HTTP/2 通信的最小單位,每個幀都包含幀頭,至少也會標識出當前幀所屬的數據流。
-
1.0 傳輸的是文本,而 2 中傳的則是二進制數據,效率更高。並有新的壓縮算法。
-
-
-
消息:與邏輯請求或響應消息對應的完整的一系列幀。
-
數據流:已建立的連接內的雙向字節流,可以承載一條或多條消息。
-
交錯發送,接受方重組。
-
-
HTTP/2 連接都是永久的,而且僅需要每個來源一個連接
-
流控制:阻止發送方向接收方發送大量數據的機制
-
伺服器推送
HTTPS 概述#
-
HTTPS : Hypertext Transfer Protocol Secure
-
經過 TSL/SSL 加密
-
對稱加密:加密和解密都是使用同一個密鑰
-
非對稱加密:加密和解密需要使用兩個不同的密鑰:公鑰(public key)和私鑰(private key)
常見場景分析#
靜態資源#
以 今日頭條 為例,打開網路面板查看其請求,找到 css 文件的請求。
可以看到返回的狀態碼為 200,那麼是不是真的發起了請求呢(旁邊的括號就說了,從磁碟快取)
由上圖響應頭,可以看出:
- 快取策略?
- 強快取(max-age=xxxxx)
- Cache-control:換算一下,1 年
- 強快取(max-age=xxxxx)
- 其他信息?
- 允許所有域名訪問(access-control-allow-origin)
- 資源類型:css(content-type)
靜態資源方案:快取 + CDN + 檔名 hash
- CDN:Content Delivery Network
- 通過用戶就近性和伺服器負載的判斷,CDN 確保內容以一種極為高效的方式為用戶的請求提供服務
那麼快取期那麼久,怎麼保證用戶拿到的內容是最新的呢?
檔名 hash,當檔案內容有變化時檔名變換 / 加上版本號,這樣快取中的檔案就無法 match,就只能重新請求了。
登錄 - 跨域#
跨域問題,導致了請求方法為 OPTION
協議、主機名、端口任意一者不同都會出現跨域問題(HTTP 的默認端口號 443)
解決跨域問題#
-
跨源資源共享(CORS)( Cross-Origin Resource Sharing )
-
跨源資源共享
(CORS)(或通俗地譯為跨域資源共享)是一種基於 HTTP 頭的機制,該機制通過允許伺服器標示除了它自己以外的其它origin(域,協議和端口),這樣瀏覽器可以訪問加載這些資源。跨源資源共享還通過一種機制來檢查伺服器是否會允許要發送的真實請求,該機制通過瀏覽器發起一個到伺服器托管的跨源資源的 "預檢" 請求。在預檢中,瀏覽器發送的頭中標示有 HTTP 方法和真實請求中會用到的頭。出於安全性,瀏覽器限制腳本內發起的跨源 HTTP 請求。 例如,
XMLHttpRequest
和 Fetch API 遵循同源策略。這意味著使用這些 API 的 Web 應用程序只能從加載應用程序的同一個域請求 HTTP 資源,除非響應報文包含了正確 CORS 響應頭。 -
預請求:獲知伺服器是否允許該跨源請求(複雜請求)
-
相關協議頭
- access-control-....
-
-
代理伺服器
- 同源策略是瀏覽器的安全策略,不是 HTTP 的
-
Iframe 諸多不便
如上圖,登錄時向什麼地址做了什麼動作?
- 使用了 post 方法
- 目標域名:https://sso.toutiao.com
- 目標為:path/quick_login/v2/
攜帶了哪些信息,返回了哪些信息?
- 攜帶信息
- Post body,數據格式為 form
- 希望獲取的數據格式為 json
- 已有的 cookie
- 返回信息
- 數據格式 json
- 種 cookie 的信息
那麼下一次進入頁面的時候,為什麼能夠記住登錄態呢?
鑒權#
- Session + cookie (大部分這種門戶網站)
- 用戶發起提交請求給伺服器,包括用戶名密碼等等
- 伺服器處理,鑒別其正確性,若正確則返回 Session 將其種到 cookie(Set-Cookie = ......)
- 用戶再發送時:GET Cookie=....
- 伺服器處理鑒別後返回一些登錄信息的
- JWT(JSON web token)
- 伺服器本地不會存儲
- 返回的 token 唯一性,登錄時間短等
- SSO:單點登錄(Single Sign On)
如圖,講解的很清楚。
實際應用#
XMLHttpRequest - Web API 接口參考 | MDN (mozilla.org)
AJAX之XHR#
- XHR: XMLHttpRequest
- readyState
0 | UNSENT | 代理被創建,但尚未調用 open () 方法。 |
1 | OPENED | open () 方法已經被調用。 |
2 | HEADERS_RECEIVED | send () 方法已經被調用,並且頭部和狀態已經可獲得。 |
3 | LOADING | 下載中;responseText 屬性已經包含部分數據。 |
4 | DONE | 下載操作已完成。 |
AJAX 之 Fetch#
- XMLHttpRequet 的升級版
- 使用 Promise
- 模塊化設計,Response,Request,Header 對象
- 通過數據流處理對象,支持分塊讀取
node 中標準庫: HTTP/HTTPS#
- 默認模塊,無需安裝其他依賴
功能有限 / 不是十分友好
常用的請求庫: axios#
- 起步 | Axios 中文文檔
- 支持瀏覽器、nodejs 環境
- 豐富的攔截器
//全局配置
axios.defaults.baseURL = "https://api.example.com";
//添加請求攔截器
axios.interceptors.request.use(function (config) {
//在發送請求之前做些什麼
return config;
},function (error) {
//對請求錯誤做些什麼
return Promise.reject(error );
});
//發送請求
axios( {
method: 'get',
url: 'http://test.com',
responseType: 'stream
}).then( function(response) {
response.data.pipe( fs.createWriteStream('ada_lovelace.jpg'))
});
網路優化#
-
HTTP/2 - A Real-World Performance Test and Analysis | CSS-Tricks - CSS-Tricks
-
預解析、預連接等
-
重試是保證穩定的有效手段,但要防止其加劇惡劣情況(比如網路連接就是斷開了)。
-
快取合理使用,作為最後一道防線。
了解更多#
不止 HTTP 協議一個選擇#
擴展 - 通信方式#
WebSocket#
- 瀏覽器與伺服器進行全雙工通訊的網路技術
- 典型場景:實時性要求高,例如聊天室
- URL 使用 **ws://** 或 wss:// 等開頭
UDP#
QUIC:Quick UDP Internet Connection 基於 UDP
- 0-RTT 建聯(首次建聯除外)。
- 類似 TCP 的可靠傳輸。
- 類似 TLS 的加密傳輸,支持完美前向安全。
- 用戶空間的擁塞控制,最新的 BBR 算法。
- 支持 h2 的基於流的多路復用,但沒有 TCP 的 HOL 問題。
- 前向糾錯 FEC。
- 類似 MPTCP 的 Connection migration。
- 應用暫不多
總結感想#
今天講師小姐姐聲音超溫柔的介紹了 HTTP 及其常見協議分析、報文結構、快取策略分析,還講解了其具體的業務場景使用。
本文引用的內容大部分來自楊超男老師的課 ——HTTP 實用指南