HTTP協議-進階
{"type":"doc","content":[{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"HTTP的實體數據-內容協商"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"blockquote","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"“多用途互聯網郵件擴展”(Multipurpose Internet Mail Extensions),簡稱爲 MIME。"}]}]},{"type":"heading","attrs":{"align":null,"level":5},"content":[{"type":"codeinline","content":[{"type":"text","text":"Content-Encoding"}]},{"type":"text","text":" 就少了很多,常用的只有下面三種:"}]},{"type":"numberedlist","attrs":{"start":"1","normalizeStart":1},"content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":1,"align":null,"origin":null},"content":[{"type":"text","text":"gzip:GNU zip 壓縮格式,也是互聯網上最流行的壓縮格式;"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":2,"align":null,"origin":null},"content":[{"type":"text","text":"deflate:zlib(deflate)壓縮格式,流行程度僅次於 gzip;"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":3,"align":null,"origin":null},"content":[{"type":"text","text":"br:一種專門爲 HTTP 優化的新壓縮算法(Brotli)。"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":5},"content":[{"type":"codeinline","content":[{"type":"text","text":"Accept"}]},{"type":"text","text":" <=> "},{"type":"codeinline","content":[{"type":"text","text":"Content-Type"}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Accept 是客戶端可接受的MIME type,對應的是響應報文裏 "},{"type":"codeinline","content":[{"type":"text","text":"Content-Type"}]},{"type":"text","text":"。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"Content-type"}]},{"type":"text","text":":"}]},{"type":"numberedlist","attrs":{"start":"1","normalizeStart":1},"content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":1,"align":null,"origin":null},"content":[{"type":"text","text":"text:文本格式的可讀數據,text/html、text/plain、text/css"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":2,"align":null,"origin":null},"content":[{"type":"text","text":"image:圖像文件,image/gif、image/jpeg、image/png"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":3,"align":null,"origin":null},"content":[{"type":"text","text":"audio/video:音頻和視頻數據,audio/mpeg、video/mp4"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":4,"align":null,"origin":null},"content":[{"type":"text","text":"application:數據格式不固定,必須由上層應用程序來解釋。application/json、application/javascript、application/pdf;application/octet-stream即不透明的二進制數據。"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":5},"content":[{"type":"codeinline","content":[{"type":"text","text":"Accept-Encoding"}]},{"type":"text","text":" <=>"},{"type":"codeinline","content":[{"type":"text","text":"Content-Encoding"}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"Accept-Encoding"}]},{"type":"text","text":": 該字段標記的是客戶端支持的壓縮格式"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"Content-Encoding"}]},{"type":"text","text":":"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"numberedlist","attrs":{"start":"1","normalizeStart":1},"content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":1,"align":null,"origin":null},"content":[{"type":"text","text":"gzip:GNU zip 壓縮格式,也是互聯網上最流行的壓縮格式;"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":2,"align":null,"origin":null},"content":[{"type":"text","text":"deflate:zlib(deflate)壓縮格式,流行程度僅次於 gzip;"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":3,"align":null,"origin":null},"content":[{"type":"text","text":"br:一種專門爲 HTTP 優化的新壓縮算法(Brotli)。"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":5},"content":[{"type":"codeinline","content":[{"type":"text","text":"Accept-Language"}]},{"type":"text","text":" <=> "},{"type":"codeinline","content":[{"type":"text","text":"Content-Language"}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"對應客戶端支持的語言和響應的語言類型:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"type-subtype"}]},{"type":"text","text":":en-US 美式英語、en-GB 英式英語、zh-CN 漢語"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/resource/image/b2/58/b2118315a977969ddfcc7ab9d26cb358.png","alt":null,"title":null,"style":null,"href":null,"fromPaste":true,"pastePass":false}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"blockquote","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"1. 數據類型表示實體數據的內容是什麼,使用的是 MIME type,相關的頭字段是 Accept 和 Content-Type;"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"2. 數據編碼表示實體數據的壓縮方式,相關的頭字段是 Accept-Encoding 和 Content-Encoding;"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"3. 語言類型表示實體數據的自然語言,相關的頭字段是 Accept-Language 和 Content-Language;"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"4. 字符集表示實體數據的編碼方式,相關的頭字段是 Accept-Charset 和 Content-Type;"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"5. 客戶端需要在請求頭裏使用 Accept 等頭字段與服務器進行“內容協商”,要求服務器返回最合適的數據;"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"6. Accept 等頭字段可以用“,”順序列出多個可能的選項,還可以用“;q=”參數來精確指定權重。"}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"horizontalrule"},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"HTTP傳輸大文件的方法"}]},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"範圍請求"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"“Transfer-Encoding: chunked”和“Content-Length”這兩個字段是互斥的,也就是說響應報文裏這兩個字段不能同時出現,一個響應報文的傳輸要麼是長度已知,要麼是長度未知(chunked),這一點一定要記住。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":5},"content":[{"type":"codeinline","content":[{"type":"text","text":"Transfer-Encoding: chunked"}]},{"type":"text","text":" 分塊傳輸的編碼規則:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"numberedlist","attrs":{"start":"1","normalizeStart":1},"content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":1,"align":null,"origin":null},"content":[{"type":"text","text":"每個分塊包含兩個部分,長度頭和數據塊;"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":2,"align":null,"origin":null},"content":[{"type":"text","text":"長度頭是以 CRLF (回車換行,即\\r\\n)結尾的一行明文,用16進制數字表示長度;"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":3,"align":null,"origin":null},"content":[{"type":"text","text":"數據塊緊跟在長度頭後,最後也用CRLF結尾,但數據不包含CRLF;"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":4,"align":null,"origin":null},"content":[{"type":"text","text":"最後用一個長度爲0的塊表示結束,即“0\\r\\n\\r\\n”"}]}]}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/resource/image/25/10/25e7b09cf8cb4eaebba42b4598192410.png","alt":"img","title":null,"style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"horizontalrule"},{"type":"heading","attrs":{"align":null,"level":5},"content":[{"type":"codeinline","content":[{"type":"text","text":"Range "}]},{"type":"text","text":" <=>"},{"type":"codeinline","content":[{"type":"text","text":"Acceot-Range: bytes"}]},{"type":"text","text":" & "},{"type":"codeinline","content":[{"type":"text","text":"Content-Range: bytes 0-31/96"}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"Range"}]},{"type":"text","text":":"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"\"0-”表示從文檔起點到文檔終點,相當於“0-99”,即整個文件;"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"“10-”是從第 10 個字節開始到文檔末尾,相當於“10-99”;"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"“-1”是文檔的最後一個字節,相當於“99-99”;"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"“-10”是從文檔末尾倒數10個字節,相當於“90-99”。"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"服務器對"},{"type":"codeinline","content":[{"type":"text","marks":[{"type":"strong"}],"text":"Range"}],"marks":[{"type":"strong"}]},{"type":"text","marks":[{"type":"strong"}],"text":"的處理"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"numberedlist","attrs":{"start":"1","normalizeStart":1},"content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":1,"align":null,"origin":null},"content":[{"type":"text","text":"檢查是否合法,是否在文件的範圍內,如果越界返回狀態碼 416,表示“你的範圍請求有誤,我無法處理,請再檢查一下”;"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":2,"align":null,"origin":null},"content":[{"type":"text","text":"如果範圍正確,服務器返回對應範圍內的數據,狀態碼是 "},{"type":"codeinline","content":[{"type":"text","text":"206 Partial Content"}]},{"type":"text","text":" 表示只是原數據的一部分。"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":3,"align":null,"origin":null},"content":[{"type":"text","text":"服務器添加響應頭字段 "},{"type":"codeinline","content":[{"type":"text","text":"Content-Range"}]},{"type":"text","text":",告訴片段的實際偏移量和資源的總大小;"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"請求:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"http"},"content":[{"type":"text","text":"GET /16-2 HTTP/1.1\nHost: www.chrono.com\nRange: bytes=0-31"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"響應:"}]},{"type":"codeblock","attrs":{"lang":"http"},"content":[{"type":"text","text":"HTTP/1.1 206 Partial Content\nContent-Length: 32\nAccept-Ranges: bytes\nContent-Range: bytes 0-31/96\n\n// this is a plain text json doc"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"horizontalrule"},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"多段數據"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":5},"content":[{"type":"codeinline","content":[{"type":"text","text":"multipart/byteranges"}]},{"type":"text","text":" 表示報文的body是由多段自己序列組成的,還需要配合 "},{"type":"codeinline","content":[{"type":"text","text":"boundary=xxx"}]},{"type":"text","text":"給出段之間的分隔標記"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/resource/image/ff/37/fffa3a65e367c496428f3c0c4dac8a37.png","alt":"img","title":null,"style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"請求:"}]},{"type":"codeblock","attrs":{"lang":"http"},"content":[{"type":"text","text":"GET /16-2 HTTP/1.1\nHost: www.chrono.com\nRange: bytes=0-9, 20-29"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"響應:"}]},{"type":"codeblock","attrs":{"lang":"http"},"content":[{"type":"text","text":"HTTP/1.1 206 Partial Content\nContent-Type: multipart/byteranges; boundary=00000000001\nContent-Length: 189\nConnection: keep-alive\nAccept-Ranges: bytes\n\n\n--00000000001\nContent-Type: text/plain\nContent-Range: bytes 0-9/96\n\n// this is\n--00000000001\nContent-Type: text/plain\nContent-Range: bytes 20-29/96\n\next json d\n--00000000001--"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"blockquote","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"1. 壓縮 HTML 等文本文件是傳輸大文件最基本的方法;"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"2. 分塊傳輸可以流式收發數據,節約內存和帶寬,使用響應頭字段“Transfer-Encoding: chunked”來表示,分塊的格式是 16 進制長度頭 + 數據塊;"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"3. 範圍請求可以只獲取部分數據,即“分塊請求”,實現視頻拖拽或者斷點續傳,使用請求頭字段“Range”和響應頭字段“Content-Range”,響應狀態碼必須是 206;"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"4. 也可以一次請求多個範圍,這時候響應報文的數據類型是“multipart/byteranges”,body 裏的多個部分會用 boundary 字符串分隔。"}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"horizontalrule"},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"HTTP的連接管理"}]},{"type":"heading","attrs":{"align":null,"level":5},"content":[{"type":"text","marks":[{"type":"italic"}],"text":"短連接"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"因爲客戶端與服務器的整個連接過程很短暫,不會與服務器保持長時間的連接狀態,所以就被稱爲“短連接”(short-lived connections)。早期的 HTTP 協議也被稱爲是“無連接”的協議。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"短連接的缺點"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"TCP 建立連接要有“三次握手”,發送3個數據包,需要 1個RTT;關閉連接是“四次揮手,需要2個RTT。每次發送HTTP請求的時候都重新建立和關閉連接,這就帶來了傳輸效率低的問題。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":5},"content":[{"type":"text","marks":[{"type":"italic"}],"text":"長連接"},{"type":"text","text":" Connection: keep-alive"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"針對短連接暴露出的缺點,HTTP 協議就提出了“長連接”的通信方式,也叫“持久連接”(persistent connections)、“連接保活”(keep alive)、“連接複用”(connection reuse)。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"複用同一個連接來完成多次HTTP的請求。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"長連接的缺點"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"服務器不會主動關閉對應的連接,需要客戶端發送"},{"type":"codeinline","content":[{"type":"text","text":"Connection: close"}]},{"type":"text","text":"字段,服務器在響應的時候也會加上對應的字段,然後就關閉TCP連接。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"解決服務器不主動關閉的策略(Nginx):"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"numberedlist","attrs":{"start":"1","normalizeStart":1},"content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":1,"align":null,"origin":null},"content":[{"type":"text","text":"使用"},{"type":"codeinline","content":[{"type":"text","text":"keepalive_timeout"}]},{"type":"text","text":"指令,設置長連接的超市時間,如果在一段時間內連接上沒有任何數據收發就主動斷開連接,避免空閒連接佔用系統資源。"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":2,"align":null,"origin":null},"content":[{"type":"text","text":"使用"},{"type":"codeinline","content":[{"type":"text","text":"keepalive_requests"}]},{"type":"text","text":"指令,設置長連接上可發送的最大請求次數。比如設置成1000,那麼當Nginx在這個連接上處理了1000個請求後,也會主動斷開連接。"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/resource/image/57/b4/57b3d80234a1f1b8c538a376aa01d3b4.png","alt":"短連接和長連接","title":null,"style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"隊頭阻塞(Head-of-line blocking)"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"隊頭阻塞是由HTTP基本的“請求-應答”模式所導致的。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"因爲HTTP規定報文必須是“一發一收”的形式,這就會形成一個先進先出的“串行”隊列。隊列裏的請求沒有輕重緩急的優先級,只有入隊的先後順序,排在最前面的請求被最優先處理。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/resource/image/6a/72/6a6d30a89fb085d5f1773a887aaf5572.png","alt":"隊頭阻塞","title":null,"style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"解決方案:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"numberedlist","attrs":{"start":"1","normalizeStart":1},"content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":1,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"“併發連接”(concurrent connections)"},{"type":"text","text":",也就是同時對一個域名發起多個長連接,用數量來解決質量的問題。"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":2,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"“域名分片”(domain sharding)"},{"type":"text","text":"技術,還是用數量來解決質量的思路。"}]}]}]},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"小結"}]},{"type":"blockquote","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"1. 早期的HTTP協議使用短連接,收到響應後就立即關閉連接,效率很低;"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"2. HTTP/1.1默認啓用長連接,在一個連接上收發多個請求響應,提高了傳輸效率;"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"3. 服務器會發送“Connection: keep-alive\"字段表示啓用了長連接;"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"4. 報文頭裏如果有“Connection: close”就意味着長連接即將關閉;"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"5. 過多的長連接會佔用服務器資源,所以俯臥起會用一些廁率有選擇的關閉長連接;"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"6. “隊頭阻塞”問題會導致性能下降,可以用“併發連接”和“域名分片”技術緩解。"}]}]},{"type":"horizontalrule"},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"HTTP的重定向和跳轉"}]},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"重定向"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"需要在狀態碼爲301(永久重定向)、302(臨時重定向)的情況下,配合"},{"type":"codeinline","content":[{"type":"text","text":"location"}]},{"type":"text","text":"字段纔會起效,對於用戶來說是無感知的,重定向的地址:有一個相對地址和一個絕對地址(URI),在"},{"type":"codeinline","content":[{"type":"text","text":"location"}]},{"type":"text","text":"字段不完整的時候會自動計算對應的相對位置。"}]},{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"301:永久重定向"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"302:臨時重定向"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"303:See other 要去重定向後的請求方法改爲Get✔️方法,訪問一個結果頁面,避免 POST/PUT 重複操作;"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"304:Not Modified,未修改,使用已有的緩存;"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"307:與302類似,但重定向後請求裏的方法和實體不允許變動,含義比302明確;"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"308:類似 307,不允許重定向後的請求變動,但是與301一樣是永久重定向"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"第一個問題"},{"type":"text","marks":[{"type":"strong"}],"text":"性能損耗"},{"type":"text","text":":重定向會出現兩個請求,除了304,對於服務器來說還是會增加一定的壓力的,產生"},{"type":"text","marks":[{"type":"strong"}],"text":"性能損耗"},{"type":"text","text":"的問題;"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"第二個問題循環跳轉:瀏覽器能檢查對應的循環跳轉的現象;"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"blockquote","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"1. 重定向是服務器發起的跳轉,要求客戶端改用新的URI重新發送請求,通常會自動進行,"},{"type":"text","marks":[{"type":"strong"}],"text":"用戶是無感知的"},{"type":"text","text":";"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"2. 302/302是最常用的重定向狀態碼,分別是“永久重定向”和“臨時重定向”;"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"3. 響應頭字段Location只是了要跳轉的URI,可以用絕對或相對的形式;"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"4. 重定向可以把一個URL指向另一個URI,也可以把多個URI指向同一個URI,用途很多;"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"5. 使用重定向時需要當心性能損耗,還要避免出循環跳轉。"}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"horizontalrule"},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"HTTP的Cookie機制"}]},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"`Cookie` <=> `Set-Cookie`"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/resource/image/9f/a4/9f6cca61802d65d063e24aa9ca7c38a4.png","alt":"img","title":null,"style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":5},"content":[{"type":"text","text":"Cookie屬性"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"http"},"content":[{"type":"text","text":"HTTP/1.1 200\nSet-Cookie: key=value, Max-Age=10; Expires=Fri, 08-Jun-22 08:19:00 GMT; Domain=www.example.com; Path=/; HttpOnly; SameSite=Strict;"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"Expires"}]},{"type":"text","text":"和"},{"type":"codeinline","content":[{"type":"text","text":"Max-Age"}]},{"type":"text","text":"都能控制Cookie的有效期,但是瀏覽器會優先採用 Max-Age計算有效期;"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":5},"content":[{"type":"codeinline","content":[{"type":"text","text":"HttpOnly"}]},{"type":"text","text":" => 防範XSS(跨站腳本)攻擊"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"blockquote","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"寫過前端的同學一定知道,在 JS 腳本里可以用 document.cookie 來讀寫 Cookie 數據,這就帶來了安全隱患,有可能會導致“跨站腳本”(XSS)攻擊竊取數據。"}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":">"}]},{"type":"blockquote","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"屬性“"},{"type":"text","marks":[{"type":"strong"}],"text":"HttpOnly"},{"type":"text","text":"”會告訴瀏覽器,此 Cookie 只能通過瀏覽器 HTTP 協議傳輸,禁止其他方式訪問,瀏覽器的 JS 引擎就會禁用 document.cookie 等一切相關的 API,腳本攻擊也就無從談起了。"}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":5},"content":[{"type":"codeinline","content":[{"type":"text","text":"SameSite"}]},{"type":"text","text":" => 防範XSRF(跨站請求僞造)攻擊"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"numberedlist","attrs":{"start":"1","normalizeStart":1},"content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":1,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"SameSite=Strict"}]},{"type":"text","text":":嚴格限制Cookie不能隨着跳轉鏈接跨站發送"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":2,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"SameSite=Lax"}]},{"type":"text","text":":允許 GET/HEAD 等安全方法,但是禁止POST跨站發送"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":5},"content":[{"type":"codeinline","content":[{"type":"text","text":"Secure"}]},{"type":"text","text":" 僅能使用HTTPS協議加密傳輸"}]},{"type":"blockquote","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"1. "},{"type":"codeinline","content":[{"type":"text","text":"Cookie"}]},{"type":"text","text":" 是服務器委託瀏覽器儲存的一些數據,讓服務器有了“記憶能力”;"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"2. 響應報文使用 "},{"type":"codeinline","content":[{"type":"text","text":"Set-Cookie"}]},{"type":"text","text":" 字段發送“"},{"type":"codeinline","content":[{"type":"text","text":"key=value"}]},{"type":"text","text":"”形式的"},{"type":"codeinline","content":[{"type":"text","text":"Cookie"}]},{"type":"text","text":"值;"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"3. 請求報文裏用 "},{"type":"codeinline","content":[{"type":"text","text":"Cookie"}]},{"type":"text","text":" 字段發送多個 "},{"type":"codeinline","content":[{"type":"text","text":"Cookie"}]},{"type":"text","text":" 值;"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"4. 爲了保護 "},{"type":"codeinline","content":[{"type":"text","text":"Cookie"}]},{"type":"text","text":",還要給它設置有效期、作用域等屬性,常用的有"},{"type":"codeinline","content":[{"type":"text","text":"Max-Age"}]},{"type":"text","text":"、"},{"type":"codeinline","content":[{"type":"text","text":"Expires"}]},{"type":"text","text":"、"},{"type":"codeinline","content":[{"type":"text","text":"Domain"}]},{"type":"text","text":"、"},{"type":"codeinline","content":[{"type":"text","text":"HttpOnly"}]},{"type":"text","text":"等;"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"5. Cookie最基本的用途是身份識別,實現有狀態會話事務。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"italic"}],"text":"Cookie 並不屬於 HTTP 標準(RFC6265,而不是 RFC2616/7230)"}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"horizontalrule"},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"HTTP的緩存控制"}]},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"HTTP緩存的分類:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":5},"content":[{"type":"text","text":"私有瀏覽器緩存(Private browser caches)"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"這是在客戶端瀏覽器才能緩存的資源;對應的是頭字段中的private"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":5},"content":[{"type":"text","text":"共享代理緩存(Shared proxy caches)"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"保存的資源是爲了重複使用的緩存;主要是在代理服務器上,對應是頭字段中的public"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"如何觸發HTTP的緩存"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"狀態爲200 的GET響應,例如HTML文件;"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"永久重定向的響應:301;"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"錯誤響應:404;"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"不完全的響應:206(Partial Content);"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"其他定義需要緩存的資源;"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"服務器的緩存控制"}]},{"type":"codeblock","attrs":{"lang":"http"},"content":[{"type":"text","text":"HTTP/1.1 200\nCache-Control: max-age=30, no-store, no-cache, must-revalidate, proxy-revalidate, public"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"max-age"}]},{"type":"text","text":":用於控制HTTP緩存,相對於服務器的響應時間;"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"public/private"}]},{"type":"text","text":":public在代理服務器和中間節點都能緩存,但是private只有在目標客戶端可以緩存;"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"no-store"}]},{"type":"text","text":":"},{"type":"text","marks":[{"type":"strong"}],"text":"不允許緩存"},{"type":"text","text":",用於變化非常頻繁的數據,例如秒殺頁面;"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"no-cache"}]},{"type":"text","text":":"},{"type":"text","marks":[{"type":"strong"}],"text":"可以緩存"},{"type":"text","text":",但在使用之前要去服務器驗證是否過期,是否有最新的版本;"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"must-revalidate"}]},{"type":"text","text":":如果緩存不過期就可以繼續使用,但過期了還想使用需要找服務器驗證;"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"proxy-revalidate"}]},{"type":"text","text":":與must-revalidate類似,但是隻有公共資源可以在代理服務器緩存,僅限public的配置的資源;"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/resource/image/1b/99/1b4f48bc0d8fb9a08b45d1f0deac8a99.png","alt":"img","title":null,"style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"客戶端的緩存控制"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"第二次訪問同一個頁面的時候,就會觸發瀏覽器的緩存;"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"blockquote","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Ctrl+F5 的“強制刷新”,其實是瀏覽器想服務器發送了一個"},{"type":"codeinline","content":[{"type":"text","text":"Cache-Control: no-cache"}]},{"type":"text","text":"的請求,更新本地的資源,其含義與"},{"type":"codeinline","content":[{"type":"text","text":"max-age=0"}]},{"type":"text","text":"是基本一樣的。"}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"瀏覽器訪問一個頁面的時候,先是通過對應的DNS查找對應的服務器地址,然後查找緩存中是否存在對應的資源,如果有就訪問緩存,這個時候對緩存資源進行驗證,如果過期就會去服務器拿最新的資源,否則就是返回緩存中的資源。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"條件請求"}]},{"type":"codeblock","attrs":{"lang":"http"},"content":[{"type":"text","text":"If-Modified-Since: Mon, 27 Jul 2020 10:53:40 GMT\nIf-None-Match: W/\"5f1eb234-b7e\""}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"條件請求的兩個字段需要配合"},{"type":"codeinline","content":[{"type":"text","text":"ETag"}]},{"type":"text","text":"和"},{"type":"codeinline","content":[{"type":"text","text":"Last-modified"}]},{"type":"text","text":"才能起效,在第一次請求的時候,服務器返回上面兩個字段;再次請求資源的時候,瀏覽器會帶上這兩個資源,使用"},{"type":"codeinline","content":[{"type":"text","text":"If-modified-since"}]},{"type":"text","text":"和"},{"type":"codeinline","content":[{"type":"text","text":"If-none-Match"}]},{"type":"text","text":"來驗證資源十分過期。如果服務器返回 304 則讀取瀏覽器的緩存文件。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"強、弱 ETag"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"強 ETage 要求資源在字節級別必須完全相符,弱 ETag 在值前面有一個 "},{"type":"codeinline","content":[{"type":"text","text":"W/"}]},{"type":"text","text":" 標記,只要求資源在語義上沒有變化,但內部可能會有部分發生了改變。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"blockquote","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"1. 緩存是優化系統性能的重要手段,HTTP 傳輸的每一個環節中都可以有緩存;"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"2. 服務器使用“Cache-Control”設置緩存策略,常用的是“max-age”,表示資源的有效期;瀏覽器收到數據就會存入緩存,如果沒過期就可以直接使用,過期就要去服務器驗證是否仍然可用;"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"3. 驗證資源是否失效需要使用“條件請求”,常用的是“if-Modified-Since”和“If-None-Match”,收到 304 就可以複用緩存裏的資源;"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"4. 驗證資源是否被修改的條件有兩個:“Last-modified”和“ETag”,需要服務器預先在響應報文裏設置,搭配條件請求使用;"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"5. 瀏覽器也可以發送“Cache-Control”字段,使用“max-age=0”或“no_cache”刷新數據。"}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"horizontalrule"},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"HTTP的代理服務"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"代理的功能:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"負載均衡是最近基本的功能"}]},{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"健康檢查:使用“心跳”等機制監控後端服務器,發現有故障就及時“踢出”集羣,保證服務高可用;"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"安全防護:保護被代理的後端服務器,限制 IP 地址或流量,抵禦網絡攻擊和過載;"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"加密卸載:對外網使用 SSL/TLS 加密通信認證,而在安全的內網不加密,消除加解密成本;"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"數據過濾:攔截上下行的數據,任意指定策略修改請求或者響應;"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"內容緩存:暫存、複用服務器響應,這個與第 20 講密切相關,我們稍後再說。"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":5},"content":[{"type":"text","text":"代理服務器的頭字段"},{"type":"codeinline","content":[{"type":"text","text":"Via"}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"經過代理服務器的資源會在Via字段中添加代理服務器的身份信息,是一個鏈表。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"blockquote","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"1. HTTP 代理就是客戶端和服務器通信鏈路中的一箇中間環節,爲兩端提供“代理服務”;"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"2. 代理處於中間層,爲 HTTP 處理增加了更多的靈活性,可以實現負載均衡、安全防護、數據過濾等功能;"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"3. 代理服務器需要使用字段“Via”標記自己的身份,多個代理會形成一個列表;"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"4. 如果想要知道客戶端的真實 IP 地址,可以使用字段“X-Forwarded-For”和“X-Real-IP”;"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"5. 專門的“代理協議”可以在不改動原始報文的情況下傳遞客戶端的真實 IP。"}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"horizontalrule"},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"HTTP的緩存代理"}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"源服務器的緩存控制"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"“private”表示緩存只能在客戶端保存,是用戶“私有”的,不能放在代理上與別人共享。而“public”的意思就是緩存完全開放,誰都可以存,誰都可以用。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"“proxy-revalidate”只要求代理的緩存過期後必須驗證,客戶端不必回源,只驗證到代理這個環節就行了。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"“s-maxage”(s 是 share 的意思,注意 maxage 中間沒有“-”),只限定在代理上能夠存多久,而客戶端仍然使用“max-age”。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"“no-transform”。代理有時候會對緩存下來的數據做一些優化,比如把圖片生成 png、webp 等幾種格式,方便今後的請求處理,而“no-transform”就會禁止這樣做,不許“偷偷摸摸搞小動作”。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/resource/image/09/35/09266657fa61d0d1a720ae3360fe9535.png","alt":"img","title":null,"style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"客戶端的緩存控制"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/resource/image/47/92/47c1a69c800439e478c7a4ed40b8b992.png","alt":"img","title":null,"style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"horizontalrule"},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"參考資料:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"極客時間《透視 HTTP 協議》"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"link","attrs":{"href":"https://developer.mozilla.org/en-US/docs/Web/HTTP/Caching","title":""},"content":[{"type":"text","text":"MDN-HTTP-Caching"}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}}]}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.