乾貨HTTP/2.0,騙你是小狗

面試官:http/1.0和http/2.0區別是什麼?css

你:html

  • 解決 HTTP 中的隊頭阻塞問題;前端

  • 二進制協議
    面試

  • http/2.0 的首部還會被深度壓縮。這將顯著減小傳輸中的冗餘字節
    算法

  •  多路複用
    promise

你覺得你備幾條答案就完事了嗎🤡,咱能不能有點出息,稍微詳細一點能夠不?又沒讓你現場調試http/2.0慌個毛線啊~🗣
老規矩啊,一會兒沒看懂的,或者腦殼放空不能吸取知識的時候,別來打我啊,請你收藏下來慢慢看, 耐心!!! 耐心!!! 耐心!!!

三言兩語http1.0和http/2.0

🎄http/0.9 :只支持get方法,不支持多媒體內容的 MIME 類型、各類 HTTP 首部,或者版本號,只是爲了獲取html對象。瀏覽器

🌸http/1.0 :添加了版本號、各類 HTTP 首部、一些額外的方法,以及對多媒體對象的處理。緩存

🍄http/1.0+ :keep-alive 鏈接、虛擬主機支持,以及代理鏈接支持都被加入到 HTTP 之中等等。安全

🍁http/1.1: 重點關注的是校訂 HTTP 設計中的結構性缺陷,明確語義,引入重要 的性能優化措施,並刪除一些很差的特性:如Entity tag,If-Unmodified-Since, If-Match, If-None-Match;請求頭引入了range頭域,它容許只請求資源的某個部分(206);新增了更多的狀態碼;Host頭處理(400)性能優化

🌺HTTP/2.0 被寄予了以下指望:

  • 相比於使用 TCP 的 HTTP/1.1,最終用戶可感知的多數延遲都有可以量化的顯 著改善;

  • 解決 HTTP 中的隊頭阻塞問題;

  • 並行的實現機制不依賴與服務器創建多個鏈接,從而提高 TCP 鏈接的利用率,

    特別是在擁塞控制方面;

  • 保留 HTTP/1.1 的語義,能夠利用已有的文檔資源(如上所述),包括(但不限於)

    HTTP 方法、狀態碼、URI 和首部字段;

  • 明肯定義 HTTP/2.0 和 HTTP/1.x 交互的方法,特別是經過中介時的方法(雙向);

  • 明確指出它們能夠被合理使用的新的擴展點和策略。

http/2.0到底有什麼?

http/2分層

http/2 大體能夠分爲兩部分:分幀層,即 h2 多路複用能力的核心部分;數據或 http 層,其中包含傳統上被認爲是 HTTP 及其關聯數據的部分。 

二進制協議:

 h2 的分幀層是基於幀的二進制協議。這方便了機器解析,可是肉眼識別起來比較困難。

首部壓縮:

僅僅使用二進制協議彷佛還不夠,h2 的首部還會被深度壓縮。這將顯著減小傳輸中的冗餘字節 

 多路複用 :

在你喜好的調試工具裏查看基於 h2 傳輸的鏈接的時候,你會發現請求和響應交織在一塊兒。

 加密傳輸:

線上傳輸的絕大部分數據是加密過的,因此在中途讀取會更加困難。

鏈接

鏈接是全部 HTTP/2 會話的基礎元素,其定義是客戶端初始化的一個 TCP/IP socket,客戶端 是指發送 HTTP 請求的實體。這和 h1 是同樣的,不過與徹底無狀態的 h1 不一樣的是,h2 把它所承載的幀(frame)和流(stream)共同依賴的鏈接層元素捆綁在一塊兒,其中既包含鏈接層設置也包含首部表。 

判斷是否支持http/2.0
🍏協議發現——識別終端是否支持你想使用的協議——會比較棘手。HTTP/2 提供兩種協
議發現的機制。
🍐在鏈接不加密的狀況下,客戶端會利用 Upgrade 首部來代表指望使用 h2。若是服務器 也能夠支持 h2,它會返回一個「101 Switching Protocols」(協議轉換)響應。這增長了 一輪完整的請求-響應通訊。
🍑 若是鏈接基於 TLS,狀況就不一樣了。客戶端在 ClientHello 消息中設置 ALPN (Application-Layer Protocol Negotiation,應用層協議協商)擴展來代表指望使用 h2 協 議,服務器用一樣的方式回覆。

 爲了向服務器雙重確認客戶端支持 h2,客戶端會發送一個叫做 connection preface(鏈接 前奏)的魔法字節流,做爲鏈接的第一份數據。這主要是爲了應對客戶端經過純文本的 HTTP/1.1 升級上來的狀況。該字節流用十六進制表示以下:

0x505249202a20485454502f322e300d0a0d0a534d0d0a0d0a複製代碼

解碼爲 ASCII 是:

PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n 複製代碼

這個字符串的用處是,若是服務器(或者中間網絡設備)不支持 h2,就會產生一個顯式錯誤。這個消息特地設計成 h1 消息的樣式。若是運行良好的 h1 服務器收到這個字符串,它會阻塞這個方法(PRI)或者版本(HTTP/2.0),並返回錯誤,可讓 h2 客戶端明確地知道發生了什麼錯誤。 

這個魔法字符串會有一個 SETTINGS 緊隨其後。服務器爲了確認它能夠支持 h2,會聲明收到客戶端的 SETTINGS 幀,並返回一個它本身的 SETTINGS 幀(反過來也須要確認), 而後確認環境正常,能夠開始使用 h2。 (注意⚠️:SETTINGS 幀是個很是重要的幀,http/2.0有十幾個幀,不一樣的幀表明不同的狀態功能)

HTTP/2 是基於幀(frame)的協議。採用分幀是爲了將重要信息都封裝起來,讓協議的解析方能夠輕鬆閱讀、解析並還原信息。 相比之下,h1 不是基於幀的,而是以 文本分隔。 看看下面的簡單例子:

GET / HTTP/1.1 <crlf>
Host: www.example.com <crlf>
Connection: keep-alive <crlf>
Accept: text/html,application/xhtml+xml,application/xml;q=0.9... <crlf>
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_4)... <crlf>
Accept-Encoding: gzip, deflate, sdch <crlf>
Accept-Language: en-US,en;q=0.8 <crlf>
Cookie: pfy_cbc_lb=p-browse-w; customerZipCode=99912|N; ltc=%20;...<crlf> 複製代碼

解析這種數據用不着什麼高科技,但每每速度慢且容易出錯。你須要不斷讀入字節,直到 遇到分隔符爲止(這裏是指 <crlf>),同時還要考慮一些不太守規矩的客戶端,它們會只 發送 <lf>。

解析 h1 的請求或響應可能出現下列問題:

 • 一次只能處理一個請求或響應,完成以前不能中止解析。

• 沒法預判解析須要多少內存。這會帶來一系列問題:你要把一行讀到多大的緩衝區裏。

若是行太長會發生什麼;應該增長並從新分配內存,仍是返回 400 錯誤。爲了解決這些問題,保持內存處理的效率和速度可不簡單。 

從另外一方面來講,有了幀,處理協議的程序就能預先知道會收到什麼。基於幀的協議,特別是 h2,開始有固定長度的字節,其中包含表示整幀長度的字段。

來,咱們看一下幀結構🤓

  • Length: 3 字節   表示幀負載的長度(取值範圍爲 2^ 14~2^24-1 字節)。 請注意,2^14 字節是默認的最大幀大小,若是須要更大的幀,必須在 SETTINGS 幀中設置 。

  • Type 1 字節  當前幀類型

  • Flags1 字節  具體幀類型的標識

  • R 1 位  保留位,不要設置,不然可能帶來嚴重後果

  •  Stream Identifier: 31 位  每一個流的惟一 ID 

  • Frame Payload長度可變   真實的幀內容,長度是在 Length 字段中設置的 

 由於規範嚴格明確,因此解析邏輯大概是這樣:

loop
   Read 9 bytes off the wire                          //讀前9個字節
   Length = the first three bytes                     //長度值爲前3字節
   Read the payload based on the length.              //基於長度讀負載
   Take the appropriate action based on the frame type. // 根據幀類型採起對應操做
end loop 			複製代碼

http/1有個特性叫管道化(pipelining),容許一次發送一組請求,可是隻能按照發送順序依次接 收響應。並且,管道化備受互操做性和部署的各類問題的困擾,基本沒有實用價值。 在請求應答過程當中,若是出現任何情況,剩下全部的工做都會被阻塞在那次請求應答之 後。這就是「隊頭阻塞」.它會阻礙網絡傳輸和 Web 頁面渲染,直至失去響應。爲了防止 這種問題,現代瀏覽器會針對單個域名開啓 6 個鏈接,經過各個鏈接分別發送請求。

它實 現了某種程度上的並行,可是每一個鏈接仍會受到「隊頭阻塞」的影響。 因爲 h2 是分幀的, 請求和響應能夠交錯甚至多路複用。多路複用有助於解決相似隊頭阻塞的問題。 
說了半天隊頭阻塞的過程是怎樣的呢?
我怎麼會讓大家一臉懵逼的去百度呢,來來來,往下看


借老哥一張圖: Head of line blocking


  • 圖中第一種請求方式,就是單次發送request請求,收到response後再進行下一次請求,顯示是很低效的。
  • 因而http1.1提出了管線化(pipelining)技術,就是如圖中第二中請求方式,一次性發送多個request請求。
  • 然而pipelining在接收response返回時,也必須依順序接收,若是前一個請求遇到了阻塞,後面的請求即便已經處理完畢了,仍然須要等待阻塞的請求處理完畢。這種狀況就如圖中第三種,第一個請求阻塞後,後面的請求都須要等待,這也就是隊頭阻塞(Head of line blocking)。
  • 爲了解決上述阻塞問題,http2中提出了多路複用(Multiplexing)技術,Multiplexing是通訊和計算機網絡領域的專業名詞。http2中將多個請求複用同一個tcp連接中,將一個TCP鏈接分爲若干個流(Stream),每一個流中能夠傳輸若干消息(Message),每一個消息由若干最小的二進制幀(Frame)組成。也就是將每一個request-response拆分爲了細小的二進制幀Frame,這樣即便一個請求被阻塞了,也不會影響其餘請求,如圖中第四種狀況所示。

HTTP/2 規範對流(stream)的定義是:「HTTP/2 鏈接上獨立的、雙向的幀序列交換。」你能夠將流看做在鏈接上的一系列幀,它們構成了單獨的 HTTP 請求和響應。若是客戶端想 要發出請求,它會開啓一個新的流。而後,服務器將在這個流上回復。這與 h1 的請求 / 響應流程相似,重要的區別在於,由於有分幀,因此多個請求和響應能夠交錯,而不會互相阻塞。 

看到這裏,是否是開始對以前看到的幀,多路複用模糊了,怎麼又來了個流?阿西吧,別慌,讓我給你解釋解釋🤨

流(stream),一個完整的請求-響應數據交互過程,具備以下幾個特色:

  1. 雙向性:同一個流內,可同時發送和接受數據;
  2. 有序性:幀(frames)在流上的發送順序很重要. 接收方將按照他們的接收順序處理這些frame. 特別是HEADERS和DATA frame的順序, 在協議的語義上顯得尤其重要.

流的建立:流能夠被客戶端或服務器單方面創建, 使用或共享;
流的關閉:流也能夠被任意一方關閉;

敲黑板,畫重點!!!別再混淆了!

多路複用:一個鏈接同一時刻能夠被多個流使用。
流的併發性:某一時刻,鏈接上流的併發數。

借老哥一張圖: http/2.0流


咱再強調一下多路複用的好處:

  1. 減小服務端鏈接壓力,減小佔用內存,提高鏈接吞吐量;
  2. 鏈接數的減小改善了網絡擁塞情況,慢啓動時間減小,擁塞和丟包恢復速度更快;
  3. 避免鏈接頻繁建立和關閉(三次鏈接、四次揮手);

鏈接、流和幀的關係

  1. 一個鏈接同時被多個流複用;
  2. 一個流表明一次完整的請求/響應過程,包含多個幀;
  3. 一個消息被拆分封裝成多個幀進行傳輸; 


消息

HTTP 消息泛指 HTTP 請求或響應。 流是用來傳輸一對請求 / 響 應消息的。一個消息至少由 HEADERS 幀(它初始化流)組成,而且能夠另外包含 CONTINUATIONDATA 幀,以及其餘的 HEADERS 幀。 


h1 的請求和響應都分紅消息首部和消息體兩部分;與之相似,h2 的請求和響應分紅HEADERS 幀DATA 幀

h1 把消息分紅兩部分:請求 / 狀態行;首部。h2 取消了這種區分,並把這些行變成了 魔法僞首部。舉個例子,HTTP/1.1 的請求和響應多是這樣的:

GET / HTTP/1.1
     Host: www.example.com
     User-agent: Next-Great-h2-browser-1.0.0
     Accept-Encoding: compress, gzip
     HTTP/1.1 200 OK
     Content-type: text/plain
     Content-length: 2     ...複製代碼

在 HTTP/2 中,它等價於:

:scheme: https:method: GET
 :path: /
 :authority: www.example.com
 User-agent: Next-Great-h2-browser-1.0.0
 Accept-Encoding: compress, gzip 
 :status: 200 
 content-type: text/plain複製代碼

請注意,請求和狀態行在這裏拆分紅了多個首部,即 :scheme、:method、:path 和 :status。 同時要注意的是,http/2.0 的這種表示方式跟數據傳輸時不一樣。 

沒有分塊編碼(chunked encoding) 

在基於幀的世界裏,誰還須要分塊?只有在沒法預先知道數據長度的狀況下向對方發送 數據時,纔會用到分塊。在使用幀做爲核心協議的 h2 裏,就再也不須要它了。

再也不有101的響應
Switching Protocol 響應是 h1 的邊緣應用。它現在最多見的應用可能就是用以升級到 WebSocket 鏈接。ALPN 提供了更明確的協議協商路徑,往返的開銷也更小。 

其實如今大部分仍是都是 http/1.1, http/2.0網站很少。還好日常刷 leetcode,發現 leetcode不只用 http/2.0,還用 graphql,走在科技的前沿🤪


再來觀摩一下人家的graphql,想起來前段時間組裏叫我實現前端graphql,如今想一想就是一把辛酸淚😭


今天重點是http/2.0,就很少說graphql。有興趣老哥請點擊傳送門

流量控制

h2 的新特性之一是基於流的流量控制。不一樣於 h1 的世界,只要客戶端能夠處理,服務端就會盡量快地發送數據,h2 提供了客戶端調整傳輸速度的能力。(而且,因爲在 h2 中, 一切幾乎都是對稱的,服務端也能夠調整傳輸的速度。)WINDOW_UPDATE 幀用來指示流量控制信息。每一個幀告訴對方,發送方想要接收多少字節。 

客戶端有不少理由使用流量控制。一個很現實的緣由多是,確保某個流不會阻塞其餘流。也可能客戶端可用的帶寬和內存比較有限,強制數據以可處理的分塊來加載反而能夠提高效率。儘管流量控制不能關閉,把窗口最大值設定爲設置 2^31-1 就等效于禁用它,至少對小於 2GB 的文件來講是如此。

另外一個須要注意的是中間代理。一般狀況下,網絡內容經過代理或者 CDN 來傳輸,也許它們就是傳輸的起點或終點。因爲代理兩端的吞吐能力可能不一樣,有了流量控制,代理的兩端就能夠密切同步,把代理的壓力降到最低。 

優先級

流的最後一個重要特性是依賴關係。現代瀏覽器都通過了精心設計,首先請求網頁上最重要的元素,以最優的順序獲取資源,由此來優化頁面性能。拿到了 HTML 以後,在渲染頁面以前,瀏覽器一般還須要 CSS 和關鍵 JavaScript 這樣的東西。在沒有多路複用的時候,在它能夠發出對新對象的請求以前,須要等待前一個響應完成。有了 h2,客戶端就能夠 一次發出全部資源的請求,服務端也能夠當即着手處理這些請求。由此帶來的問題是,瀏覽器失去了在 h1 時代默認的資源請求優先級策略。假設服務器同時接收到了 100 個請求, 也沒有標識哪一個更重要,那麼它將幾乎同時發送每一個資源,次要元素就會影響到關鍵元素 的傳輸。 

h2 經過流的依賴關係來解決這個問題。經過 HEADERS 幀PRIORITY 幀,客戶端能夠明確地和服務端溝通它須要什麼,以及它須要這些資源的順序。這是經過聲明依賴關係樹 和樹裏的相對權重實現的。 

依賴關係爲客戶端提供了一種能力,經過指明某些對象對另外一些對象有依賴,告知服務器這些對象應該優先傳輸。

權重讓客戶端告訴服務器如何肯定具備共同依賴關係的對象的優先級。 

咱們來看看這個簡單的網站:

index.html
– header.jpg
– critical.js
– less_critical.js
– style.css
– ad.js
– photo.jpg 	複製代碼

在收到主體 HTML 文件以後,客戶端會解析它,並生成依賴樹,而後給樹裏的元素分配權重。這時這棵樹多是這樣的:

index.html
  – style.css
    – critical.js
      –  less_critical.js (weight 20)
      –  photo.jpg (weight 8)
      –  header.jpg (weight 8)
      –  ad.js (weight 4) 			複製代碼

在這個依賴樹裏,客戶端代表它最須要的是 style.css,其次是 critical.js。沒有這兩個文件, 它就不能接着渲染頁面。等它收到了 critical.js,就能夠給出其他對象的相對權重。權重表示服務一個對象時所須要花費的對應「努力」程度。 

服務器推送

提高單個對象性能的最佳方式,就是在它被用到以前就放到瀏覽器的緩存裏面。這正是 HTTP/2 的服務端推送的目的。推送使服務器可以主動將對象發給客戶端,這多是由於 它知道客戶端不久將用到該對象。 

若是服務器決定要推送一個對象(RFC 中稱爲「推送響應」),會構造一個 PUSH_PROMISE 幀。這個幀有不少重要屬性,列舉以下 :

  • 🐢PUSH_PROMISE 幀首部中的流 ID 用來響應相關聯的請求。推送的響應必定會對應到 客戶端已發送的某個請求。若是瀏覽器請求一個主體 HTML 頁面,若是要推送此頁面 使用的某個 JavaScript 對象,服務器將使用請求對應的流 ID 構造 PUSH_PROMISE 幀

  • 🦑PUSH_PROMISE 幀的首部塊與客戶端請求推送對象時發送的首部塊是類似的。因此客戶端有辦法放心檢查將要發送的請求。

  • 🐞被髮送的對象必須確保是可緩存的。

  • 🐙:method 首部的值必須確保安全。安全的方法就是冪等的那些方法,這是一種不改變

    任何狀態的好辦法。例如,GET 請求被認爲是冪等的,由於它一般只是獲取對象,而POST 請求被認爲是非冪等的,由於它可能會改變服務器端的狀態。

  • 🐳理想狀況下,PUSH_PROMISE 幀應該更早發送,應當早於客戶端接收到可能承載着推

    送對象的 DATA 幀。假設服務器要在發送 PUSH_PROMISE 以前發送完整的 HTML, 那客戶端可能在接收到 PUSH_PROMISE 以前已經發出了對這個資源的請求。h2 足夠健壯,能夠優雅地解決這類問題,但仍是會有些浪費。

  • 🐡PUSH_PROMISE 幀會指示將要發送的響應所使用的流 ID。 

客戶端會從 1 開始設置流 ID,以後每新開啓一個流,就會增長 2,以後一直 使用奇數。服務器開啓在 PUSH_PROMISE 中標明的流時,設置的流 ID 從 2 開始,以後一直使用偶數。這種設計避免了客戶端和服務器之間的流 ID 衝 突,也能夠輕鬆地判斷哪些對象是由服務端推送的。0 是保留數字,用於連 接級控制消息,不能用於建立新的流。 

若是客戶端對 PUSH_PROMISE 的任何元素不滿意,就能夠按照拒收緣由選擇重置這個流 (使用 RST_STREAM),或者發送 PROTOCOL_ERROR(在 GOAWAY 幀中)。常見的狀況是緩存中已經有了這個對象。而 PROTOCOL_ERROR 是專門留給 PUSH_PROMISE 涉及的協議層面問題的,好比方法不安全,或者當客戶端已經在 SETTINGS 幀中代表本身不接受推送時,仍然進行了推送。值得注意的是,服務器能夠在 PUSH_PROMISE 發送後當即啓動推送流,所以拒收正在進行的推送可能仍然沒法避免推送大量資源。推送正確的資源是不夠的,還須要保證只推送正確的資源,這是重要的性能優化手段。 

因此到底如何選擇要推送的資源?

決策的過程須要考慮到以下方面:

 • 資源已經在瀏覽器緩存中的機率

• 從客戶端看來,這些資源的優先級

• 可用的帶寬,以及其餘相似的會影響客戶端接收推送的資源 

若是用戶第一次訪問頁面時,就能向客戶端推送頁面渲染所需的關鍵 CSS 和 JS 資源,那 麼服務端推送的真正價值就實現了。不過,這要求服務器端實現足夠智能,以免「推送 承諾」(push promise)與主體 HTML 頁面傳輸競爭帶寬。

 

首部壓縮

「臃腫的消息首部」提到過,現代網頁平均包含 140 個請求,每一個 HTTP 請求 平均有 460 字節,總數據量達到 63KB。即便在最好的環境下,這也會形成至關長的延時, 若是考慮到擁擠的 WiFi 或鏈接不順暢的蜂窩網絡,那但是很是痛苦的。這些請求之間一般幾乎沒有新的或不一樣的內容,這纔是真正的浪費。因此,你們迫切渴望某種類型的壓縮。 通過屢次創新性的思考和討論,人們提出了 HPACKHPACK 是種表查找壓縮方案,它利用霍夫曼編碼得到接近 GZIP 的壓縮率。 

CRIME 攻擊告訴咱們, GZIP 也有泄漏加密信息的風 險。 CRIME 的原理是這樣的,攻擊者在請求中添加數據,觀察壓縮加密後的數據量是否會小於預期。若是變小了,攻擊者就知道注入的文本和請求中的其餘內容(好比私有的 會話 cookie)有重複。在很短的時間內,通過加密 的數據內容就能夠所有搞清楚。所以,你們放棄了已有的壓縮方案,研發出 HPACK。 

第一個請求:

:authority: www.akamai.com
     :method: GET
     :path: /
     :scheme: https
     accept: text/html,application/xhtml+xml
     accept-language: en-US,en;q=0.8
     cookie: last_page=286A7F3DE
     upgrade-insecure-requests: 1
     user-agent: Awesome H2/1.0複製代碼

第二個請求:

:authority: www.akamai.com
     :method: GET     :path: /style.css     :scheme: https     accept: text/html,application/xhtml+xml accept-language: en-US,en;q=0.8     cookie: last_page=*398AB8E8F upgrade-insecure-requests: 1 user-agent: Awesome H2/1.0 
複製代碼

能夠看到,後者的不少數據與前者重複了。第一個請求約有 220 字節,第二個約有 230 字 節,但兩者只有 36 字節是不一樣的。若是僅僅發送這 36 字節,就能夠節省約 85%的字節 數。簡而言之,HPACK 的原理就是這樣。 

http/2.0反模式

h1 下的一些性能調優辦法在 h2 下會起到副作用。 

域名拆分

域名拆分是爲了利用瀏覽器對每一個域名開啓多個鏈接的能力,以便實現資源的並行下載, 繞過 h1 的串行化下載的限制。對於包含大量小型資源的網站,廣泛的作法是拆分域名, 以利用現代瀏覽器針能對每一個域名開啓 6 個鏈接的特性。這樣實際上作到了讓瀏覽器並行 發送多個請求,以及充分利用可用帶寬的效果。由於 HTTP/2 採起多路複用,因此域名拆 分就不是必要的了,而且反而會讓協議力圖實現的目標落空。 

資源內聯

資源內聯包括把 JavaScript、樣式,甚至圖片插入到 HTML 頁面中,目的是省掉加載外部資源所需的新鏈接以及請求響應的時間。然而,有些 Web 性能的最佳實踐不推薦使用內聯,由於這樣會損失更有價值的特性,好比緩存。若是有同一個頁面上的重複訪問,緩存一般能夠減小請求數(並且可以加速頁面渲染)。儘管如此,整體來講,對那些渲染滾動 條以上區域所需的微小資源進行內聯處理還是值得的。

事實上有證據代表,在性能較弱的 設備上,緩存對象的好處不夠多,把內聯資源拆分出來並不划算。 使用 h2 時的通常原則是避免內聯,可是內聯也並不必定毫無價值。 

資源合併

資源合併意味着把幾個小文件合併成一個大文件。它與內聯很類似,旨在省掉那些加載外部資源的請求響應時間,以及解碼 / 執行那些資源所消耗的 CPU 資源。以前針對資源內聯 的規則一樣適用於資源合併,咱們可使用它來合併不是常小的文件(1KB 或更小),以及 對初始渲染很關鍵的最簡化 JavaScript/CSS 資源。 

禁用cookie的域名

經過禁用 cookie 的域名來提供靜態資源是一項標準的性能優化最佳實踐。尤爲是使用 h1 時,你沒法壓縮首部,並且有些網站使用的 cookie 大小經常超過單個 TCP 數據包的限度。 不過,在 h2 下請求首部使用 HPACK 算法被壓縮,會顯著減小巨型 cookie(尤爲是當它 們在前後請求之間保持不變)的字節數。與此同時,禁用 cookie 的域名須要額外的主機名 稱,這意味着將開啓更多的鏈接。

若是你正在使用禁用 cookie 的域名,之後有機會你可能得考慮消滅它。若是你確實不須要那些域名,最好刪掉它們。省一個字節就是一個字節。 

生成精靈圖

目前,生成精靈圖還是一種避免小資源請求過多的技術(你能看到人們樂意作什麼來優化 h1)。爲了生成精靈圖,開發者把較小的圖片拼合成較大的圖片,而後用 CSS 選擇圖片中 某個部分展現出來。依據設備及其硬件圖形處理能力的不一樣,精靈圖要麼很是高效,要麼 很是低效。若是用 h2,最佳實踐就是避免生成精靈圖;主要緣由在於,多路複用和首部壓縮去掉了大量的請求開銷。即使如此,仍是有些場景適合使用精靈圖。


性能優化因人而異 

爲了最大化 Web 性能,須要在許多變量之間取捨,包括網絡條件、設備 處理能力、瀏覽器能力,還有協議限制。這些組成了咱們所說的場景,大多數開發者 的時間遠遠不夠考慮那麼多場景。 

怎麼辦?最佳實踐的第一原則就是:測試。性能測試與監控是得到最大成果的關鍵, HTTP/2 也不例外。觀察真實用戶數據、詳盡分析各類條件、查找問題,而後解決它們。要遵循業界推薦的方式,但也不要陷入過早優化的陷阱。



it's over.

有問題,歡迎指正呀~

相關文章
相關標籤/搜索