使用 Early Hints 伺服器思考時間,加快網頁載入速度

瞭解伺服器如何傳送重要子資源的提示給瀏覽器。

巴希 (Kenji Baheux)
Kenji Baheux
巴瑞帕拉德
Barry Pollard

什麼是早期提示?

現今的網站越來越複雜。因此,伺服器必須執行非複雜工作 (例如存取資料庫,或是存取原始伺服器的 CDN) 才能為要求的網頁產生 HTML。不過,這類「伺服器思考時間」會導致瀏覽器開始轉譯網頁之前引發額外的延遲。的確,只要伺服器需要回應,連線仍會保持閒置狀態。

圖片顯示伺服器在載入網頁到載入其他資源之間需要 200 毫秒的時間差。
沒有早期提示:伺服器會封鎖所有內容,決定如何回應主要資源。

Early Hints 是一個 HTTP 狀態碼 (103 Early Hints),用來在最終回應之前傳送基本的 HTTP 回應。這樣一來,當伺服器忙著產生主要資源時,伺服器就會針對重要子資源 (例如網頁的樣式表、重要的 JavaScript) 或來源將提示傳送給瀏覽器。瀏覽器可以在等待主要資源時,使用這些提示來暖機連線並要求子資源。換句話說,Early Hints 可預先完成一些工作,加快頁面載入速度,協助瀏覽器善用這類「伺服器思考時間」。

這張圖片顯示 Early Hints 如何允許頁面傳送部分回應。
使用 Early Hints:伺服器可在決定最終回應時,提供含資源提示的部分回應

在某些情況下,根據 ShopifyCloudflare 的觀察,最大內容繪製的效能改善幅度可能會從一百毫秒,甚至快上一秒,如以下比較前後對照圖:

比較兩個網站。
在測試網站上使用 WebPageTest (Moto G4 - DSL) 進行早期提示的比較前後對照

實作早期提示

在深入探討這個主題前,請注意,如果您的伺服器可以立即傳送 200 (或其他最終回應) 回應,早期提示就沒有幫助。在這種情況下,請考慮在主要回應 (Link rel HTTP 標頭) 或主要回應 (<link> 元素) 中使用一般 link rel=preloadlink rel=preconnect。如果您的伺服器需要更多時間產生主要回應,請繼續閱讀!

要運用早期提示,第一步就是找出熱門到達網頁,也就是使用者造訪網站時通常會從哪些網頁開始。例如首頁或熱門產品資訊頁面 (如有許多使用者來自其他網站)。這些進入點的重要性比起其他網頁更為重要,這是因為使用者瀏覽您的網站時,Early Hints 的實用性會降低 (也就是說,瀏覽器將在第二或第三次瀏覽時提供所需的所有子資源)。留下良好的第一印像也是個好主意!

現在您已排定到達網頁的優先順序清單,下一步要開始找出適合使用預先連結預先載入提示的來源或子資源。這類項目通常是指對重要使用者指標帶來最大影響的來源和子資源,例如最大內容繪製首次內容繪製。具體來說,請找出會阻擋轉譯的子資源,例如同步 JavaScript、樣式表,甚至是網路字型。同樣地,您也可以找出代管子資源,對重要使用者指標產生許多貢獻的來源。注意:如果您的主要資源已經使用 <link rel=preconnect><link rel=preload>,您可以在早期提示的候選資源中將這些來源或資源納入考量。詳情請參閱這篇文章

第二步是針對可能過時或不再使用的資源或來源使用 Early Hints,降低相關風險。舉例來說,經常更新和版本化的資源 (例如 example.com/css/main.fa231e9c.css) 可能不是最佳選擇。請注意,這個問題不僅適用於早期提示,而是適用於可能存在的任何連結 rel=preloadrel=preconnect。這種詳細資料最適合自動化或範本處理。舉例來說,手動程序較有可能導致 link rel=preload 和使用資源的實際 HTML 標記之間的雜湊或版本網址不相符。

例如,請思考以下流程:

GET /main.html
Host: example.com
User-Agent: [....] Chrome/103.0.0.0 [...]

伺服器預測需要 main.abcd100.css,並建議透過 Early Hints 預先載入它:

103 Early Hints
Link: </main.abcd100.css>; rel=preload; as=style
[...]

不久後,系統就會放送網頁 (包括已連結的 CSS)。很抱歉,這項 CSS 資源經常更新,且主要資源已比預測 CSS 資源 (abcd100) 的五個版本提前 (abcd105)。

200 OK
[...]
<HTML>
<head>
   <title>Example</title>
   <link rel="stylesheet" href="/main.abcd105.css">

一般來說,請盡量爭取穩定的資源和來源相當穩定,且多數結果與主要資源結果無關。如有需要,你可以考慮將重要資源分成兩部分:一個專為 Early Hints 設計的穩定部分,以及在瀏覽器收到主要資源後擷取的動態部分:

<HTML>
<head>
   <title>Example</title>
   <link rel="stylesheet" href="/main.css">
   <link rel="stylesheet" href="/experimental.3eab3290.css">

最後,在伺服器端,找出支援 Early Hints 的瀏覽器傳送的主要資源要求,並立即以 103 Early Hints 做出回應。在 103 回應中,加入相關的預先連線和預先載入提示。主要資源準備就緒後,請針對一般回應進行後續追蹤 (例如,如果成功 200 OK)。為了顧及回溯相容性,建議您在最終回應中加入 Link HTTP 標頭,甚至可以加入產生主要資源部分顯而易見的重要資源 (例如,如果您按照「在兩個部分分割」建議中操作了金鑰資源的動態部分)。如下所示:

GET /main.html
Host: example.com
User-Agent: [....] Chrome/103.0.0.0 [...]
103 Early Hints
Link: <https://fonts.google.com>; rel=preconnect
Link: </main.css>; rel=preload; as=style
Link: </common.js>; rel=preload; as=script

稍後:

200 OK
Content-Length: 7531
Content-Type: text/html; charset=UTF-8
Content-encoding: br
Link: <https://fonts.google.com>; rel=preconnect
Link: </main.css>; rel=preload; as=style
Link: </common.js>; rel=preload; as=script
Link: </experimental.3eab3290.css>; rel=preload; as=style
<HTML>
<head>
   <title>Example</title>
   <link rel="stylesheet" href="/main.css">
   <link rel="stylesheet" href="/experimental.3eab3290.css">
   <script src="/common.js"></script>
   <link rel="preconnect" href="https://fonts.googleapis.com">

瀏覽器支援

雖然所有主要瀏覽器都支援 103 Early Hints,但 Early Hint 可使用的指令會因瀏覽器而異:

預先連線支援:

瀏覽器支援

  • 103
  • 103
  • 120
  • 17

預先載入支援:

瀏覽器支援

  • 103
  • 103
  • x

伺服器支援

以下概略說明常見 OSS HTTP 伺服器軟體中 Early Hints 的支援等級:

輕鬆啟用早期提示

如果您使用下列其中一種 CDN 或平台,可能就不需要手動導入早期提示。如要瞭解該解決方案是否支援早期提示,或查看僅列舉部分內容,請參閱解決方案供應商的線上說明文件:

避免無法支援早期提示的用戶端問題

100 範圍顯示的資訊 HTTP 回應屬於 HTTP 標準,但某些較舊的用戶端或機器人可能就較為困難,因為在 103 Early Hints 推出前,這類回應很少用於一般網路瀏覽。

只有在回應傳送 sec-fetch-mode: navigate HTTP 要求標頭的用戶端時,才發出 103 早期提示必須確保只會針對可等待後續回應的較新用戶端傳送這類提示。此外,由於 Early Hints 只支援導航要求 (請參閱目前的限制),因此這有個附加優點,就是避免在其他要求中傳送這些要求。

此外,建議僅透過 HTTP/2 或 HTTP/3 連線傳送早期提示

進階模式

如果您已將「早期提示」功能應用於主要的到達網頁,但有意發掘更多商機,不妨採用以下進階模式。

對於在一般使用者歷程中,位於第「n」n網頁要求的訪客,您不妨針對頁面中較深或更深入的內容,調整「早期提示」回應,也就是對優先順序較低的資源使用早期提示。由於我們建議將重點放在優先順序高且會妨礙顯示的子資源或來源,因此這聽起來可能違反直覺。不過,要是訪客瀏覽了一段時間,他們的瀏覽器可能已具備所有重要資源。以此為基礎,您不妨將注意力轉向優先順序較低的資源。舉例來說,這可能表示使用 Early Hints 載入產品圖片,或是只用較不常見使用者互動所需的其他 JS/CSS。

目前限制

以下是在 Chrome 中實作早期提示的限制:

  • 僅適用於瀏覽要求 (也就是頂層文件的主要資源)。
  • 只支援 preconnectpreload,也就是不支援 prefetch
  • 早期提示在最終回應中接著執行跨來源重新導向,會導致 Chrome 捨棄透過 Early Hints 取得的資源和連線。

其他瀏覽器也設有類似的限制,並進一步限制 103 份早期提示只能用於 preconnect

後續步驟

我們可能會依據社群感興趣的內容,在導入早期提示時提供下列功能:

  • 透過子資源要求傳送的早期提示。
  • 透過 iframe 主要資源要求傳送的早期提示。
  • 支援早期提示中的預先擷取功能。

歡迎提供意見,瞭解應優先處理哪些部分,以及如何進一步改善早期提示。

與 H2/推送的關係

如果您熟悉已淘汰的 HTTP2/推送功能,可能會想瞭解早期提示的差異。雖然 Early Hints 需要往返瀏覽器才能開始擷取重要的子資源,但 HTTP2/Push 伺服器便可開始將子資源與回應一併推送。這聽起來不錯,但這卻造成關鍵的結構缺點:HTTP2/推播期間,要避免推送瀏覽器現有的子資源非常困難。這種「過度推送」的影響會降低網路頻寬用量的效率,進而大幅降低了效能方面的益處。整體來說,Chrome 資料顯示 HTTP2/推播功能確實導致網路效能的淨負面。

相較之下,Early Hints 結合了傳送初步回應的功能和提示,讓瀏覽器可以掌控擷取或連線的實際需求,因此成效較佳。雖然 Early Hints 並未涵蓋 HTTP2/Push 理論中可能解決的所有用途,但我們認為「早期提示」是更實際可行的解決方案,以加快瀏覽速度。

縮圖圖片來源:Pierre Bamin