计网 - HTTP 协议_强制缓存和协商缓存的区别
文章目錄
- Pre
- 請求響應和長連接
- HTTP 2.0 的多路復用
- HTTP 方法和 RestFul 架構
- HTTP 方法
- 緩存
- 強制緩存
- 協商緩存
- 總結
Pre
超文本傳輸協議(HyperText Transfer Protocol,HTTP)是目前使用最廣泛的應用層協議。在網站、App、開放接口中都可以看到它。HTTP 協議設計非常簡單,但是涵蓋的內容很多。
1990 年蒂姆·伯納斯·李開發了第一個瀏覽器,書寫了第一個 Web 服務器程序和第一張網頁。網頁用的語言后來被稱作超文本標記語言(HTML),而在服務器和客戶端之間傳輸網頁的時候,伯納斯·李沒有直接使用傳輸層協議,而是在 TCP 的基礎上構造了一個應用層協議,這個就是超文本傳輸協議 HTTP。
萬維網(World Wide Web, WWW)是伯納斯·李對這一系列發明,包括 Web 服務、HTTP 協議、HTML 語言等一個體系的綜合。
請求響應和長連接
HTTP 協議采用請求/返回模型。客戶端(通常是瀏覽器)發起 HTTP 請求,然后 Web 服務端收到請求后將數據回傳。
HTTP 的請求和響應都是文本,你可以簡單認為 HTTP 協議利用 TCP 協議傳輸文本。當用戶想要看一張網頁的時候,就發送一個文本請求到 Web 服務器,Web 服務器解析了這段文本,然后給瀏覽器將網頁回傳。
那么這里有一個問題,是不是每次發送一個請求,都建立一個 TCP 連接呢? 當然不能這樣,為了節省握手、揮手的時間。當瀏覽器發送一個請求到 Web 服務器的時候,Web 服務器內部就設置一個定時器。在一定范圍的時間內,如果客戶端繼續發送請求,那么服務器就會重置定時器。如果在一定范圍的時間內,服務器沒有收到請求,就會將連接斷開。這樣既防止浪費握手、揮手的資源,同時又避免一個連接占用時間過長無法回收導致內存使用效率下降。
這個能力可以利用 HTTP 協議頭進行配置,比如下面這條請求頭:
Keep-Alive: timeout=5s會告訴 Web 服務器連接的持續時間是 5s,如果 5s 內沒有請求,那么連接就會斷開。
HTTP 2.0 的多路復用
Keep-Alive 并不是伯納斯·李設計 HTTP 協議時就有的能力。伯納斯·李設計的第一版 HTTP 協議是 0.9 版,后來隨著協議逐漸完善,有了 1.0 版。而 Keep-Alive 是 HTTP 1.1 版增加的功能,目的是應對越來越復雜的網頁資源加載。從 HTTP 協議誕生以來,網頁中需要的資源越來越豐富,打開一張頁面需要發送的請求越來越多,于是就產生了 Keep-Alive 的設計。
同樣,當一個網站需要加載的資源較多時,瀏覽器會嘗試并發發送請求(利用多線程技術)。瀏覽器會限制同時發送并發請求的數量,通常是 6 個,這樣做一方面是對用戶本地體驗的一種保護,防止瀏覽器搶占太多網絡資源;另一方面也是對站點服務的保護,防止瞬時流量過大。
在 HTTP 2.0 之后,增加了多路復用能力。和 RPC 框架時提到的多路復用類似,請求、返回會被拆分成切片,然后混合傳輸。這樣請求、返回之間就不會阻塞。你可以思考,對于一個 TCP 連接,在 HTTP 1.1 的 Keep-Alive 設計中,第二個請求,必須等待第一個請求返回。如果第一個請求阻塞了,那么后續所有的請求都會阻塞。而 HTTP 2.0 的多路復用,將請求返回都切分成小片,這樣利用同一個連接,請求相當于并行的發出,互相之間不會有干擾。
HTTP 方法和 RestFul 架構
伴隨著 HTTP 發展,也誕生了一些著名的架構,比如 RestFul。在面試中,經常會遇到 RestFul,RestFul 是 3 個單詞的合并縮寫:
-
Re(Representational)
-
st(State)
-
Ful(Transfer)
這個命名非常有趣,讓我聯想到 grep 命令的命名,global regular pattern match。這是一種非常高端的命名技巧,提取詞匯中的一個部分組合成為一個讀起來朗朗上口的新詞匯,建議在實戰命名的時候也可以考慮試試。
在 RestFul 架構中,狀態僅僅存在于服務端,前端無狀態。
狀態(State)可以理解為業務的狀態,這個狀態是由服務端管理的。這個無狀態和服務端目前倡導的無狀態設計不沖突,現在服務端倡導的無狀態設計指的是容器內的服務沒有狀態,狀態全部存到合適的存儲中去。所以 Restful 中的 State,是服務端狀態。
前端(瀏覽器、應用等)沒有業務狀態,卻又要展示內容,因此前端擁有的是狀態的表示,也就是 Representation。
比如一個訂單,狀態存在服務端(數據庫中),前端展示訂單只需要部分信息,不需要全部信息。前端只需要展示數據,展示數據需要服務端提供。所以服務端提供的不是狀態,而是狀態的表示。
前端沒有狀態,當用戶想要改變訂單狀態的時候,比如支付,這個時候前端就向服務端提交表單,然后服務端觸發狀態的變化。這個過程我們稱為轉化(Transfer)。從這個角度來看,Restful 講的是一套前端無狀態、服務端管理狀態,中間設計轉化途徑(請求、函數等)的架構方法。這個方法可以讓前后端職責清晰,前端負責渲染, 服務端負責業務。前端不需要業務狀態,只需要展示。服務端除了關心狀態,還要提供狀態的轉換接口。
HTTP 方法
在 Restful 架構中,除了約定了上述整體架構方案之外,還約束了一些實現細節,比如用名詞性的接口和 HTTP 方法來設計服務端提供的接口。
我們用 GET 獲取數據,或者進行查詢。比如下面這個例子,就是在獲取 id 為 123 的訂單數據:
GET /order/123GET 是 HTTP 方法,/order 是一種名詞性質的命名。這樣設計語義非常清晰,這個接口是獲取訂單的數據(也就是訂單的 Representation 用的)。
對于更新數據的場景,按照 HTTP 協議的約定,PUT 是一種冪等的更新行為,POST 是一種非冪等的更新行為。舉個例子:
PUT /order/123 {...訂單數據}上面我們用 PUT 更新訂單,如果訂單 123 還沒有創建,那么這個接口會創建訂單。如果 123 已經存在,那么這個接口會更新訂單 123 的數據。為什么是這樣?因為 PUT 代表冪等,對于一個冪等的接口,請求多少遍最終的狀態是一致的,也就是說操作的都是同一筆訂單。
如果換成用 POST 更新訂單:
POST /order{...訂單數據}POST 代表非冪等的設計,像上面這種用 POST 提交表單的接口,調用多次往往會產生多個訂單。也就是非冪等的設計每次調用結束后都會產生新的狀態。
另外在 HTTP 協議中,還約定了 DELETE 方法用于刪除數據。其實還有幾個方法, 比如 OPTIONS、PATCH等等。
緩存
在 HTTP 的使用中,我們經常會遇到兩種緩存,強制緩存和協商緩存,接下來舉兩個場景來說明。
強制緩存
舉個例子: 公司用版本號管理某個對外提供的 JS 文件。比如說 libgo.1.2.3.js,就是 libgo 的 1.2.3 版本。其中 1 是主版本,2 是副版本,3 是補丁編號。每次你們有任何改動,都會更新 libgo 版本號。在這種情況下,當瀏覽器請求了一次 libgo.1.2.3.js 文件之后,還需要再請求一次嗎?
整理下我們的需求,瀏覽器在第一次進行了GET /libgo.1.2.3.js這個操作后,如果后續某個網頁還用到了這個文件(libgo.1.2.3.js),我們不再發送第二次請求。這個方案要求瀏覽器將文件緩存到本地,并且設置這個文件的失效時間(或者永久有效)。這種請求過一次不需要再次發送請求的緩存模式,在 HTTP 協議中稱為強制緩存。當一個文件被強制緩存后,下一次請求會直接使用本地版本,而不會真的發出去。
使用強制緩存時要注意,千萬別把需要動態更新的數據強制緩存。一個負面例子就是小明把獲取用戶信息數據的接口設置為強制緩存,導致用戶更新了自己的信息后,一直要等到強制緩存失效才能看到這次更新。
協商緩存
我們再說一個場景:小明開發了一個接口,這個接口提供全國省市區的 3 級信息。先問你一個問題,這個場景可以用強制緩存嗎?小明一開始覺得強制緩存可以,然后突然有一天接到運營的通知,某市下屬的兩個縣合并了,需要調整接口數據。小明錯手不急,更新了接口數據,但是數據要等到強制緩存失效。
為了應對這種場景,HTTP 協議還設計了協商緩存。協商緩存啟用后,第一次獲取接口數據,會將數據緩存到本地,并存儲下數據的摘要。第二次請求時,瀏覽器檢查到本地有緩存,將摘要發送給服務端。服務端會檢查服務端數據的摘要和瀏覽器發送來的是否一致。如果不一致,說明服務端數據發生了更新,服務端會回傳全部數據。如果一致,說明數據沒有更新,服務端不需要回傳數據。
從這個角度看,協商緩存的方式節省了流量。對于小明開發的這個接口,多數情況下協商緩存會生效。當小明更新了數據后,協商緩存失效,客戶端數據可以馬上更新。和強制緩存相比,協商緩存的代價是需要多發一次請求。
總結
目前 HTTP 協議已經發展到了 2.0 版本,不少網站都更新到了 HTTP 2.0。大部分瀏覽器、CDN 也支持了 HTTP 2.0。 可以自行查閱更多關于 HTTP 2.0 解決隊頭阻塞、HPack 壓縮算法、Server Push 等資料。
另外 HTTP 3.0 協議也在建設當中,HTTP 3.0 對 HTTP 2.0 兼容,主要調整發生在網絡底層。HTTP 3.0 開始采用 UDP 協議,并在 UDP 協議之上,根據 HTTP 協議的需求特性,研發了網絡層、應用層去解決可靠性等問題。
總結
以上是生活随笔為你收集整理的计网 - HTTP 协议_强制缓存和协商缓存的区别的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 计网 - 网络 I/O 模型:BIO、N
- 下一篇: 架构漫谈 - 数据治理核心思路及解决方案