HTTP協議學習---(三)進階篇

新人歡發表於2020-11-05

一 HTTP協議body資料格式

http協議是明文傳輸的,為了具體描述body中的資料需要在header中加入一些描述欄位。

1 MIME type
MIME 把資料分成了八大類,每個大類下再細分出多個子類,形式是“type/subtype”的字串(常用的四大類以下)
text:即文字格式的可讀資料,我們最熟悉的應該就是 text/html 了,表示超文字文件,此外還有純文字 text/plain、樣式表 text/css 等。
image:即影像檔案,有 image/gif、image/jpeg、image/png 等。
audio/video:音訊和視訊資料,例如 audio/mpeg、video/mp4 等。
application:資料格式不固定,可能是文字也可能是二進位制,必須由上層應用程式來解釋。常見的有 application/json,application/javascript、application/pdf 等,另外,如果實在是不知道資料是什麼型別,就會是 application/octet-stream,即不透明的二進位制資料。

2 Encoding type
gzip:GNU zip 壓縮格式,也是網際網路上最流行的壓縮格式;
deflate:zlib(deflate)壓縮格式,流行程度僅次於 gzip;
br:一種專門為 HTTP 優化的新壓縮演算法(Brotli)

3 請求與響應的協商
HTTP 協議也使用 Accept 請求頭欄位和 Content 實體頭欄位,用於客戶端和伺服器就語言與編碼進行“內容協商”
例如訪問https://www.baidu.com/
在這裡插入圖片描述
在這裡插入圖片描述

其中q指的是權重,與對應的型別中間用’;’隔開,最大值也是預設值為1,最小值為0表示不接受,*/*指的是除前面之外的其他型別。
Accept表示客戶端希望得到的MIME type,中間用’,’隔開。
Content-Type表示實際返回的MIME type。
Accept-Encoding表示客戶端支援的壓縮演算法(省略表示不支援壓縮)
Content-Encoding表示服務端返回資料採用的壓縮格式(省略表示不壓縮)。
Accept-Language表示希望返回的語言
Content-Language表示實際使用的語言型別
Accept-Charset表示支援的字符集(基本不用,字符集基本都支援)
沒有Content-Charset,會在Content-Type最後直接加上返回的字符集。

不同伺服器協商的結果是不一定的,有的時候,伺服器會在響應頭裡多加一個 Vary 欄位,記錄伺服器在內容協商時參考的請求頭欄位,給出一點資訊,例如:
Vary: Accept-Encoding,User-Agent,Accept
這個 Vary 欄位表示伺服器依據了 Accept-Encoding、User-Agent 和 Accept 這三個頭欄位,然後決定了發回的響應報文。

二 HTTP協議大檔案傳輸方式

1 資料壓縮
Accept-Encoding中用到的基本只對純文字資料有很好的壓縮效率,但是不適用於音訊視訊類的大型二進位制資料,因為本身壓縮率已經很高了,用gzip等可能會起到反作用。

2 chunked
Transfer-Encoding: chunked,把大檔案拆分成小檔案分塊傳輸,然後再由接收端拼接。注意,因為http是一問一答的形式,所以在接收端未完全獲取所有的資料塊完成拼接之前,這個請求就一直不會完成。這裡的分塊與TCP的分塊沒有任何關係,TCP本身就會對內容進行分塊傳輸,但是HTTP不關注這些內容,相當於HTTP本身先對資料進行分塊,下層的TCP在對分塊之後的資料在分塊。
Transfer-Encoding: chunked”和“Content-Length”這兩個欄位是互斥的,也就是說響應報文裡這兩個欄位不能同時出現。

3 資料塊的格式
①每個分塊包含兩個部分,長度頭和資料塊;
②長度頭是以 CRLF(回車換行,即\r\n)結尾的一行明文,用 16 進位制數字表示長度;
③資料塊緊跟在長度頭後,最後也用 CRLF 結尾,但資料不包含 CRLF;
④最後用一個長度為 0 的塊表示結束,即“0\r\n\r\n”。
在這裡插入圖片描述

4 範圍請求
在處理完大資料傳輸之後,對於音訊視訊可能存在獲取大資料塊中的某些資料塊,所以需要用到範圍請求。範圍請求不是 Web 伺服器必備的功能,可以實現也可以不實現,所以伺服器必須在響應頭裡使用欄位“Accept-Ranges: bytes”明確告知客戶端:“我是支援範圍請求的”。如果不支援的話該怎麼辦呢?伺服器可以傳送“Accept-Ranges: none”,或者乾脆不傳送“Accept-Ranges”欄位
請求頭 Range 是 HTTP 範圍請求的專用欄位,格式是“bytes=x-y”,其中的 x 和 y 是以位元組為單位的資料範圍。
注意 x、y 表示的是“偏移量”,範圍必須從 0 計數,例如前 10 個位元組表示為“0-9”,第二個 10 位元組表示為“10-19”,而“0-10”實際上是前 11 個位元組。以下為多種表達方式
①“0-”表示從文件起點到文件終點,相當於“0-99”,即整個檔案;
②“10-”是從第 10 個位元組開始到文件末尾,相當於“10-99”;
③“-1”是文件的最後一個位元組,相當於“99-99”;
④“-10”是從文件末尾倒數 10 個位元組,相當於“90-99”。
伺服器收到請求之後會做四件事:
①它必須檢查範圍是否合法,比如檔案只有 100 個位元組,但請求“200-300”,這就是範圍越界了。伺服器就會返回狀態碼 416,意思是“你的範圍請求有誤,我無法處理,請再檢查一下”。
②如果範圍正確,伺服器就可以根據 Range 頭計算偏移量,讀取檔案的片段了,返回狀態碼“206 Partial Content”,和 200 的意思差不多,但表示 body 只是原資料的一部分。
③伺服器要新增一個響應頭欄位 Content-Range,告訴片段的實際偏移量和資源的總大小,格式是“bytes x-y/length”,與 Range 頭區別在沒有“=”,範圍後多了總長度。例如,對於“0-10”的範圍請求,值就是“bytes 0-10/100”。
④剩下的就是傳送資料了,直接把片段用 TCP 發給客戶端,一個範圍請求就算是處理完了。
例:
請求
在這裡插入圖片描述

響應
在這裡插入圖片描述

5 補充
範圍請求與壓縮演算法同時使用的時候,裡面的range表示的是壓縮之前的資料塊,因為壓縮一般都是一邊壓縮一邊傳送資料,所以並不知道壓縮後總資料塊的大小。
斷點續傳的實現原理:
先傳送一個HEAD請求看伺服器是否支援chunked,如果支援,則開N個執行緒,每個執行緒的range填寫本執行緒請求資源的大小。完了之後再進行合併即可,即使中斷,也只需要再請求本執行緒的range即可。
一次請求多段資料:
需額外加入一個MIME type,multipart/byteranges”,表示報文的 body 是由多段位元組序列組成的,並且還要用一個引數“boundary=xxx”給出段之間的分隔標記。
在這裡插入圖片描述

例:
請求
在這裡插入圖片描述

響應
在這裡插入圖片描述

三 HTTP協議連線管理

1 早期的 HTTP 協議使用短連線,收到響應後就立即關閉連線,效率很低;

2 HTTP/1.1 預設啟用長連線,在一個連線上收發多個請求響應,提高了傳輸效率;

同時因為TCP有慢啟動擁塞視窗等特性,新建立的連結傳送資料一般比較慢,所以長連線會更快一些。

3 伺服器會傳送“Connection: keep-alive”欄位表示啟用了長連線;

4 報文頭裡如果有“Connection: close”就意味著長連線即將關閉;

5 過多的長連線會佔用伺服器資源,所以伺服器會用一些策略有選擇地關閉長連線;
nginx的連線處理策略:
①使用“keepalive_timeout”指令,設定長連線的超時時間,如果在一段時間內連線上沒有任何資料收發就主動斷開連線,避免空閒連線佔用系統資源。
②使用“keepalive_requests”指令,設定長連線上可傳送的最大請求次數。比如設定成 1000,那麼當 Nginx 在這個連線上處理了 1000 個請求後,也會主動斷開連線。

6 “隊頭阻塞”問題會導致效能下降,可以用“併發連線”和“域名分片”技術緩解。
隊頭阻塞是指因為http是應答模式,所以所有的請求都會排隊等待傳送,當有請求佔用時間較長時會阻塞剩餘請求,導致整體變慢。
併發連線指的是瀏覽器與一個域名建立多個連線,傳送請求時就有多個佇列分攤。
域名分片指的是如果瀏覽器限制了一個域名只能建立N個連結,那麼可以對於域名進行分片,請求時客戶端與多個域名建立連線即可。例如www.baidu.com可以被分片為www1.baidu.com www2.baidu.com,再瀏覽器層面www1與www2都指向www的IP即可

7 補充
DDOS攻擊:
利用長連線特性對伺服器建立大量的連線請求導致伺服器資源用盡從而拒絕提供服務
Connection:
請求頭中Connection除了keep-alive以及close之外,還有一個Upgrade,配合101狀態碼錶示切換協議。

四 HTTP協議重定向跳轉

1重定向是伺服器發起的跳轉,要求客戶端改用新的 URI 重新傳送請求,通常會自動進行,使用者是無感知的;

2 301/302 是最常用的重定向狀態碼,分別是“永久重定向”和“臨時重定向”;

3響應頭欄位 Location 指示了要跳轉的 URI,可以用絕對或相對的形式,一定要與3xx狀態碼連用才可以;

4重定向可以把一個 URI 指向另一個 URI,也可以把多個 URI 指向同一個 URI,用途很多;

5使用重定向時需要當心效能損耗,還要避免出現迴圈跳轉。

6 補充
300狀態碼少用,一般指返回多個可跳轉地址,讓使用者自己選擇。
重定向報文裡也可以使用Refresh欄位實現延遲重定向。
例:Refresh:5;url=xxx 表示延遲5秒後重定向到XXX
與跳轉有關的還有一個Referer和Referrer-Policy。表示瀏覽器跳轉的來源,可以用於後續統計或者防盜鏈等。

五 HTTP的COOKIE機制

1 cookie的傳遞
響應頭欄位Set-Cookie以及請求頭欄位Cookie

2 cookie的屬性
①生命週期
Expires過期時間 具體的時間
Max-age(優先使用) 相對時間 單位是秒,計算方法為瀏覽器收到報文的時
間加上過期時間計算出過期的具體時間,設定為0表示立即失效。
如果不指定這兩個屬性則表示只在瀏覽器執行期間有限,關閉瀏覽器則失效。
②作用域
Domain 所屬的域名
Path 路徑 全路徑表示/
③安全性
XSS(跨站指令碼)攻擊指的是通過JS執行指令碼document.cookie等方式獲取資料進行攻擊
HttpOnly
此 Cookie 只能通過瀏覽器 HTTP 協議傳輸,禁止其他方式訪問
SameSite
“SameSite=Strict”可以嚴格限定 Cookie 不能隨著跳轉連結跨站傳送, 而“SameSite=Lax”則略寬鬆一點,允許 GET/HEAD 等安全方法,但禁止 POST 跨 站傳送。
Secure
表示這個 Cookie 僅能用 HTTPS 協議加密傳輸,明文的 HTTP 協議會禁止傳送

六 HTTP的快取機制

1 響應頭中的Cache-Control
max-age
快取最大存活時間,單位秒。告知瀏覽器快取的持續時間
no-store
不允許瀏覽器快取該資源
no-cache
允許快取資源,但是使用前需要訪問伺服器看是否有最新的資源,如果有就用最新的,如果沒有就用瀏覽器本地的快取
must-revalidate
允許快取資源,在有效期內可以直接使用,但過了有效期就要訪問伺服器看是否允許使用。
在這裡插入圖片描述

2 請求頭中的Cache-Control
與響應頭中類似,當請求頭中如果有Cache-Control: max-age=0表示獲取最新的資源,當請求頭中有Cache-Control: no-cache含義與max-age一樣,表示請求最新的資源。

3 條件請求
與普通請求不同,成功返回的是304而不是200,200表示有新的資源
瀏覽器用“Cache-Control”做快取控制只能是重新整理資料,不能很好地利用快取資料,又因為快取會失效,使用前還必須要去伺服器驗證是否是最新版。瀏覽器可以用兩個連續的請求組成“驗證動作”:先是一個 HEAD,獲取資源的修改時間等元資訊,然後與快取資料比較,如果沒有改動就使用快取,節省網路流量,否則就再發一個 GET 請求,獲取最新的版本。但是這樣成本太高,因此 HTTP 協議就定義了一系列“If”開頭的“條件請求”欄位,專門用來檢查驗證資源是否過期,也就是校驗過期的責任交給瀏覽器。
首先請求資源第一次的響應報文需要提供兩個欄位:
Last-modified
最近一次的更新時間
ETag
資源的唯一標識,因為Last-modified只能精確到秒,在秒之內的改變無法區分。ETag有強弱之分,強表示資源在位元組級別上必須完全相同,弱表示資源整體的語義不變。
條件請求一共有 5 個頭欄位:
if-Modified-Since
If-None-Match
If-Unmodified-Since
If-Match
If-Range
注意:請求頭中同時有If-None-Match、If-Modified-Since、Cache-Control,對於伺服器來說,If-None-Match、If-Modified-Since的優先順序高,也就是即使請求頭有Cache-Control: no-cache,走的也是條件請求,而不是直接返回最新完整資料

七 HTTP的代理服務

1 代理的作用
①負載均衡 分散入口流量
②健康檢查 使用心跳機制連線後端伺服器,發現故障阻斷服務
③安全防護 限制IP或者流量
④加密解除安裝 SSL/TSL加密解密,外網加密,內網解密
⑤資料過濾 攔截資料修改欄位
⑥內容快取 快取資源減少後端壓力

2 代理資訊記錄
代理伺服器使用Via欄位表名代理身份,在請求頭中沒經過一個代理,就需要在Via欄位中追加代理的資訊。非官方通常採用“X-Forwarded-For”(只記錄IP資訊,第一個是客戶端的IP,之後是代理/伺服器的IP)和“X-Real-IP”(只記錄一個客戶端IP)

3 代理協議
因為X-Forwarded-For以及X-Real-IP這些欄位在請求頭中,如果要獲取真實客戶端IP需要解析請求頭,但在有些場景下是不允許的或者被加密了的,所以由代理軟體公司HAProxy定義了一個事實標準的代理協議。
代理協議分為兩版,V1,V2。V1是明文,V2是二進位制格式。
它在 HTTP 報文前增加了一行 ASCII 碼文字,相當於又多了一個頭。這一行文字其實非常簡單,開頭必須是“PROXY”五個大寫字母,然後是“TCP4”或者“TCP6”,表示客戶端的 IP 地址型別,再後面是請求方地址、應答方地址、請求方埠號、應答方埠號,最後用一個回車換行(\r\n)結束。這樣代理伺服器只需要解析報文前的之一行資料即可,不用理會報文內的實際資料。
例:
在這裡插入圖片描述

八 HTTP的代理快取服務

1 Cache-Control快取屬性區分
除了基本的max-age、no-store、no-cache 和 must-revalidate之外,由於加入了代理,對於一些資源代理有沒有許可權快取的許可權做的限制,private表示資源只能在客戶端快取,public表示資源可以在代理與客戶端都快取。

2 代理端快取失效後的重新驗證以及其他欄位
在這裡插入圖片描述

3 客戶端快取失效後的重新驗證
在這裡插入圖片描述

4 快取清理
比較常用的是服務端向代理伺服器傳送一個PURGE(自定義的)請求方式的請求,來刪除資源
九 HTTP2
1 http2概覽
HTTP 協議取消了小版本號,所以 HTTP/2 的正式名字不是 2.0;
HTTP/2 在“語義”上相容 HTTP/1,保留了請求方法、URI 等傳統概念;
HTTP/2 使用“HPACK”演算法壓縮頭部資訊,消除冗餘資料節約頻寬;
HTTP/2 的訊息不再是“Header+Body”的形式,而是分散為多個二進位制“幀”; HTTP/2 使用虛擬的“流”傳輸訊息,解決了困擾多年的“隊頭阻塞”問題,同時實現了“多路複用”,提高連線的利用率;
HTTP/2 也增強了安全性,要求至少是 TLS1.2,而且禁用了很多不安全的密碼套件。
2 具體實現
HTTP/2 必須先傳送一個“連線前言”字串,然後才能建立正式連線;
HTTP/2 廢除了起始行,統一使用頭欄位,在兩端維護欄位“Key-Value”的索引表,使用“HPACK”演算法壓縮頭部;
HTTP/2 把報文切分為多種型別的二進位制幀,報頭裡最重要的欄位是流識別符號,標記幀屬於哪個流;
流是 HTTP/2 虛擬的概念,是幀的雙向傳輸序列,相當於 HTTP/1 裡的一次“請求 - 應答”;
在一個 HTTP/2 連線上可以併發多個流,也就是多個“請求 - 響應”報文,這就是“多路複用”。

十 HTTP的優化

1 整體方向
效能優化是一個複雜的概念,在 HTTP 裡可以分解為伺服器效能優化、客戶端效能優化和傳輸鏈路優化;
伺服器有三個主要的效能指標:吞吐量、併發數和響應時間,此外還需要考慮資源利用率;
客戶端的基本效能指標是延遲,影響因素有地理距離、頻寬、DNS 查詢、TCP 握手等;
從伺服器到客戶端的傳輸鏈路可以分為三個部分,我們能夠優化的是前兩個部分,也就是“第一公里”和“中間一公里”;
有很多工具可以測量這些指標,伺服器端有 ab、top、sar 等,客戶端可以使用測試網站,瀏覽器的開發者工具。

2 細節
花錢購買硬體、軟體或者服務可以直接提升網站的服務能力,其中最有價值的是 CDN;
不花錢也可以優化 HTTP,三個關鍵詞是“開源”“節流”和“快取”;
後端應該選用高效能的 Web 伺服器,開啟長連線,提升 TCP 的傳輸效率;
前端應該啟用 gzip、br 壓縮,減小文字、圖片的體積,儘量少傳不必要的頭欄位;
快取是無論何時都不能忘記的效能優化利器,應該總使用 Etag 或 Last-modified 欄位標記資源;
升級到 HTTP/2 能夠直接獲得許多方面的效能提升,但要留意一些 HTTP/1 的“反模式”。

相關文章