【網絡通信 -- 直播】IM 學習系列 -- 網絡通信協議簡介(HTTP 協議 五)

【網絡通信 -- 直播】IM 學習系列 -- 網絡通信協議簡介(HTTP 協議 五)

【1】HTTP 的 Cookie 機制

【1.1】Cookie 的工作過程
涉及到響應頭字段 Set-Cookie 和請求頭字段 Cookie;
當用戶通過瀏覽器第一次訪問服務器的時候,服務器不知道用戶的身份,需要以“key=value”格式創建一個獨特的身份標識數據,然後放進 Set-Cookie 字段裏,隨着響應報文一同發給瀏覽器;瀏覽器收到響應報文,確定裏面有 Set-Cookie,便可確定這是服務器給的身份標識,於是就保存起來,下次再請求的時候就自動把這個值放進 Cookie 字段裏發給服務器;由於第二次請求裏面有了 Cookie 字段,服務器就知道這個用戶不是新人,就可以拿出 Cookie 裏的值,識別出用戶的身份,然後提供個性化的服務;通常,服務器會在響應頭裏添加多個 Set-Cookie,存儲多個“key=value”,但瀏覽器發送時不需要用多個 Cookie 字段,只要在一行裏用“;”隔開就行;

Cookie 是由瀏覽器負責存儲的,是“瀏覽器綁定”的,只能在本瀏覽器內生效;

【1.2】Cookie 的屬性
1. Cookie 的生存週期,即有效期,一旦超過這個期限瀏覽器就認爲是 Cookie 失效,在存儲裏刪除,也不會發送給服務器;Cookie 的有效期可以使用 Expires 和 Max-Age 兩個屬性來設置,“Expires”俗稱“過期時間”,用的是絕對時間點,可以理解爲“截止日期”(deadline);“Max-Age”用的是相對時間,單位是秒,瀏覽器用收到報文的時間點再加上 Max-Age,就可以得到失效的絕對時間;Expires 和 Max-Age 可以同時出現,兩者的失效時間可以一致,也可以不一致,但瀏覽器會優先採用 Max-Age 計算失效期;
2. Cookie 的作用域,讓瀏覽器僅發送給特定的服務器和 URI,避免被其他網站盜用;“Domain”和“Path”指定了 Cookie 所屬的域名和路徑,瀏覽器在發送 Cookie 前會從 URI 中提取出 host 和 path 部分,對比 Cookie 的屬性,如果不滿足條件,就不會在請求頭裏發送 Cookie;使用這兩個屬性可以爲不同的域名和路徑分別設置各自的 Cookie,通常 Path 就用一個“/”或者直接省略,表示域名下的任意路徑都允許使用 Cookie,讓服務器自行選擇;
3. Cookie 的安全性,儘量不要讓服務器以外的人看到;屬性“HttpOnly”會告訴瀏覽器,此 Cookie 只能通過瀏覽器 HTTP 協議傳輸,禁止其他方式訪問,瀏覽器的 JS 引擎就會禁用 document.cookie 等一切相關的 API,腳本攻擊也就無從談起了;屬性“SameSite”可以防範“跨站請求僞造”(XSRF)攻擊,設置成“SameSite=Strict”可以嚴格限定 Cookie 不能隨着跳轉鏈接跨站發送,而“SameSite=Lax”則略寬鬆一點,允許 GET/HEAD 等安全方法,但禁止 POST 跨站發送;屬性“Secure”,表示這個 Cookie 僅能用 HTTPS 協議加密傳輸,明文的 HTTP 協議會禁止發送,但 Cookie 本身不是加密的,瀏覽器裏還是以明文的形式存在;

【1.3】Cookie 的應用
1. Cookie 最基本的一個用途就是身份識別,保存用戶的登錄信息,實現會話事務;
2. Cookie 的另一個常見用途是廣告跟蹤;

【2】HTTP 的緩存控制

【2.1】服務器的緩存控制

緩存的運行機制


1. 瀏覽器發現緩存無數據,於是發送請求,向服務器獲取資源;
2. 服務器響應請求,返回資源,同時標記資源的有效期;
3. 瀏覽器緩存資源,等待下次重用;

HTTP 中緩存字段及其屬性
服務器標記資源有效期使用的頭字段是“Cache-Control”
“max-age=30”就是資源的有效時間,max-age 是“生存時間”,時間的計算起點是響應報文的創建時刻,而不是客戶端收到報文的時刻,即包含了在鏈路傳輸過程中所有節點所停留的時間;
no-store 不允許緩存,用於某些變化非常頻繁的數據;
no-cache 可以緩存,但在使用之前必須要去服務器驗證是否過期,是否有最新的版本;
must-revalidate 如果緩存不過期就可以繼續使用,但過期瞭如果還想用就必須去服務器驗證;

【2.2】客戶端的緩存控制

當點擊“刷新”按鈕的時候,瀏覽器會在請求頭裏加一個“Cache-Control: max-age=0”,瀏覽器就不會使用緩存,而是向服務器發請求,服務器看到 max-age=0,也就會用一個最新生成的報文迴應瀏覽器;
Ctrl+F5 的“強制刷新”其實是發了一個“Cache-Control: no-cache”,含義和“max-age=0”基本一樣,就看後臺的服務器怎麼理解,通常兩者的效果是相同的;
“前進”“後退”“跳轉”這些重定向動作中瀏覽器只用最基本的請求頭,沒有“Cache-Control”,所以就會檢查緩存,直接利用之前的資源,不再進行網絡通信;

【2.3】條件請求

HTTP 協議就定義了一系列“If”開頭的“條件請求”字段,專門用來檢查驗證資源是否過期,從而把兩個請求才能完成的工作合併在一個請求,驗證的責任也交給服務器;

條件請求一共有 5 個頭字段,最常用的是“if-Modified-Since”和“If-None-Match”,需要第一次的響應報文預先提供“Last-modified”和“ETag”,然後第二次請求時就可以帶上緩存裏的原值,驗證資源是否是最新的,如果資源沒有變,服務器就回應一個“304 Not Modified”,表示緩存依然有效,瀏覽器就可以更新一下有效期,然後使用緩存;

“Last-modified”即文件的最後修改時間;ETag 即“實體標籤”(Entity Tag)的縮寫,是資源的一個唯一標識,主要是用來解決修改時間無法準確區分文件變化的問題;比如,一個文件在一秒內修改了多次,但因爲修改時間是秒級,所以這一秒內的新版本無法區分;再比如,一個文件定期更新,但有時會是同樣的內容,實際上沒有變化,用修改時間就會誤以爲發生了變化,傳送給瀏覽器就會浪費帶寬;使用 ETag 就可以精確地識別資源的變動情況,讓瀏覽器能夠更有效地利用緩存;ETag 還有“強”“弱”之分,強 ETag 要求資源在字節級別必須完全相符,弱 ETag 在值前有個“W/”標記,只要求資源在語義上沒有變化,但內部可能會有部分發生了改變(例如 HTML 裏的標籤順序調整,或者多了幾個空格);

【3】HTTP 的代理服務

鏈條的起點還是客戶端(也就是瀏覽器),中間的角色被稱爲代理服務器(proxy server),鏈條的終點被稱爲源服務器(origin server),意思是數據的“源頭”“起源”;

【3.1】代理服務

“代理服務”就是指服務本身不生產內容,而是處於中間位置轉發上下游的請求和響應,具有雙重身份,面向下游的用戶時,表現爲服務器,代表源服務器響應客戶端的請求;而面向上游的源服務器時,又表現爲客戶端,代表客戶端發送請求;

【3.2】代理的作用
1. 負載均衡
2. 健康檢查,使用“心跳”等機制監控後端服務器,發現有故障就及時“踢出”集羣,保證服務高可用;
3. 安全防護,保護被代理的後端服務器,限制 IP 地址或流量,抵禦網絡攻擊和過載;
4. 加密卸載,對外網使用 SSL/TLS 加密通信認證,而在安全的內網不加密,消除加解密成本;
5. 數據過濾,攔截上下行的數據,任意指定策略修改請求或者響應;
6. 內容緩存,暫存、複用服務器響應;

【3.3】代理相關頭字段

1. 代理服務器需要用字段“Via”標明代理的身份;Via 是一個通用字段,請求頭或響應頭裏都可以出現,每當報文經過一個代理節點,代理服務器就會把自身的信息追加到字段的末尾,如果通信鏈路中有很多中間代理,就會在 Via 裏形成一個鏈表,這樣就可以知道報文究竟走過了多少個環節纔到達了目的地;

例如圖中有兩個代理:proxy1 和 proxy2,客戶端發送請求會經過這兩個代理,依次添加就是“Via:proxy1, proxy2”,等到服務器返回響應報文的時候就要反過來走,頭字段就是“Via:proxy2,  proxy1”;

2. “X-Forwarded-For”即“爲誰而轉發”,每經過一個代理節點就會在字段裏追加一個信息;“X-Forwarded-For”追加的是請求方的 IP 地址,在字段裏最左邊的 IP 地址就是客戶端的地址;
3. “X-Real-IP”獲取客戶端真實 IP 的手段,作用是記錄客戶端 IP 地址,沒有中間的代理信息;

【3.4】代理協議

代理協議 V1 版本
開頭是“PROXY”五個大寫字母,然後是“TCP4”或者“TCP6”,表示客戶端的 IP 地址類型,再後面是請求方地址、應答方地址、請求方端口號、應答方端口號,最後用一個回車換行(\r\n)結束;

【4】HTTP 的緩存代理

【4.1】緩存代理服務

代理服務收到源服務器發來的響應數據後需要做兩件事;
1. 把報文轉發給客戶端,2. 把報文存入自己的 Cache 裏,下一次再有相同的請求,代理服務器就可以直接發送 304 或者緩存數據,不必再從源服務器那裏獲取,從而降低了客戶端的等待時間,同時節約了源服務器的網絡帶寬;
在 HTTP 的緩存體系中,緩存代理的身份十分特殊,它“既是客戶端,又是服務器”,同時也“既不是客戶端,又不是服務器”;說它“即是客戶端又是服務器”,是因爲它面向源服務器時是客戶端,在面向客戶端時又是服務器,所以它既可以用客戶端的緩存控制策略也可以用服務器端的緩存控制策略;但緩存代理也“即不是客戶端又不是服務器”,因爲它只是一個數據的“中轉站”,並不是真正的數據消費者和生產者,所以還需要有一些新的“Cache-Control”屬性來對它做特別的約束;

代理服務器的緩存控制
1. 使用屬性“private”和“public”區分客戶端上的緩存和代理上的緩存;
“private”表示緩存只能在客戶端保存,是用戶“私有”的,不能放在代理上與別人共享;“public”表示緩存完全開放;
2. 緩存失效後的重新驗證也要區分開(即使用條件請求“Last-modified”和“ETag”),“must-revalidate”是隻要過期就必須回源服務器驗證,而新的“proxy-revalidate”只要求代理的緩存過期後必須驗證,客戶端不必回源,只驗證到代理這個環節就行了;
3. 使用屬性“s-maxage”(s 是 share 的意思,注意 maxage 中間沒有“-”)表示緩存的生存時間,只限定在代理上能夠存多久,而客戶端仍然使用“max-age”;
4. 使用屬性“no-transform”禁止代理對緩存數據的優化處理,比如把圖片生成 png、webp 等幾種格式,方便今後的請求處理;

完整的服務器端緩存控制策略,可以同時控制客戶端和代理

客戶端的緩存控制

“max-stale”表示如果代理上的緩存過期了也可以接受,但不能過期太多,超過 x 秒也會不要;
“min-fresh”表示緩存必須有效,而且必須在 x 秒後依然有效;
“only-if-cached”表示只接受代理緩存的數據,不接受源服務器的響應;如果代理上沒有緩存或者緩存過期,就應該給客戶端返回一個 504(Gateway Timeout);

參考致謝
本博客爲博主的學習實踐總結,並參考了衆多博主的博文,在此表示感謝,博主若有不足之處,請批評指正。

【1】透視HTTP協議

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章