二進(jìn)制協(xié)議:HTTP/2 是一個二進(jìn)制協(xié)議。在 HTTP/1.1 版中,報文的頭信息必須是文本(ASCII 編碼),數(shù)據(jù)體可以是文本,也可以是二進(jìn)制。HTTP/2 則是一個徹底的二進(jìn)制協(xié)議,頭信息和數(shù)據(jù)體都是二進(jìn)制,并且統(tǒng)稱為"幀",可以分為頭信息幀和數(shù)據(jù)幀。 幀的概念是它實(shí)現(xiàn)多路復(fù)用的基礎(chǔ)。
多路復(fù)用: HTTP/2 實(shí)現(xiàn)了多路復(fù)用,HTTP/2 仍然復(fù)用 TCP 連接,但是在一個連接里,客戶端和服務(wù)器都可以同時發(fā)送多個請求或回應(yīng),而且不用按照順序一一發(fā)送,這樣就避免了"隊(duì)頭堵塞"【1】的問題。
數(shù)據(jù)流: HTTP/2 使用了數(shù)據(jù)流的概念,因?yàn)?HTTP/2 的數(shù)據(jù)包是不按順序發(fā)送的,同一個連接里面連續(xù)的數(shù)據(jù)包,可能屬于不同的請求。因此,必須要對數(shù)據(jù)包做標(biāo)記,指出它屬于哪個請求。HTTP/2 將每個請求或回應(yīng)的所有數(shù)據(jù)包,稱為一個數(shù)據(jù)流。每個數(shù)據(jù)流都有一個獨(dú)一無二的編號。數(shù)據(jù)包發(fā)送時,都必須標(biāo)記數(shù)據(jù)流 ID ,用來區(qū)分它屬于哪個數(shù)據(jù)流。
頭信息壓縮: HTTP/2 實(shí)現(xiàn)了頭信息壓縮,由于 HTTP 1.1 協(xié)議不帶狀態(tài),每次請求都必須附上所有信息。所以,請求的很多字段都是重復(fù)的,比如 Cookie 和 User Agent ,一模一樣的內(nèi)容,每次請求都必須附帶,這會浪費(fèi)很多帶寬,也影響速度。HTTP/2 對這一點(diǎn)做了優(yōu)化,引入了頭信息壓縮機(jī)制。一方面,頭信息使用 gzip 或 compress 壓縮后再發(fā)送;另一方面,客戶端和服務(wù)器同時維護(hù)一張頭信息表,所有字段都會存入這個表,生成一個索引號,以后就不發(fā)送同樣字段了,只發(fā)送索引號,這樣就能提高速度了。
服務(wù)器推送: HTTP/2 允許服務(wù)器未經(jīng)請求,主動向客戶端發(fā)送資源,這叫做服務(wù)器推送。使用服務(wù)器推送提前給客戶端推送必要的資源,這樣就可以相對減少一些延遲時間。這里需要注意的是 http2 下服務(wù)器主動推送的是靜態(tài)資源,和 WebSocket 以及使用 SSE 等方式向客戶端發(fā)送即時數(shù)據(jù)的推送是不同的。
【1】隊(duì)頭堵塞:隊(duì)頭阻塞是由 HTTP 基本的“請求 - 應(yīng)答”模型所導(dǎo)致的。HTTP 規(guī)定報文必須是“一發(fā)一收”,這就形成了一個先進(jìn)先出的“串行”隊(duì)列。隊(duì)列里的請求是沒有優(yōu)先級的,只有入隊(duì)的先后順序,排在最前面的請求會被最優(yōu)先處理。如果隊(duì)首的請求因?yàn)樘幚淼奶⒄`了時間,那么隊(duì)列里后面的所有請求也不得不跟著一起等待,結(jié)果就是其他的請求承擔(dān)了不應(yīng)有的時間成本,造成了隊(duì)頭堵塞的現(xiàn)象。