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

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

Kenji Baheux
Kenji Baheux

什麼是「早期提示」?

網站變得越來越複雜。因此,我們不常需要執行一些簡單的工作 (例如存取資料庫,或存取原始伺服器的 CDN 服務),以產生所要求網頁的 HTML。遺憾的是,這樣的「伺服器思考時間」會導致瀏覽器開始轉譯網頁之前,出現額外的延遲。實際上,只要伺服器需要伺服器準備回應,連線就會有效暫停。

圖片:伺服器認為網頁載入和其他資源載入之間須耗時 200 毫秒。
沒有早期提示:系統會在伺服器上封鎖所有內容,以便判定主要資源的回應方式。

早期提示是一種 HTTP 狀態碼 (103 Early Hints),用來在最終回應之前傳送初步 HTTP 回應。這樣一來,當伺服器正忙於產生主要資源時,伺服器就會將網頁可能使用的重要子資源 (例如網頁的樣式表、重要 JavaScript) 或來源相關提示傳送給瀏覽器。瀏覽器可在等待主要資源的同時,使用這些提示暖機連線並要求子資源。換句話說,早期提示會提前執行一些工作,藉此加快網頁載入速度,從而協助瀏覽器善用這類「伺服器思考時間」。

這張圖片顯示 Early Hints 如何允許網頁傳送部分回應。
透過早期提示:伺服器可發出含有資源提示的部分回應,同時決定最終回應

根據 ShopifyCloudflare 觀察到的結果,在某些情況下,Largest Contentful Paint 的效能改善幅度可能長達數百毫秒,而快上一秒,如下圖所示:

兩個網站的比較。
使用 WebPageTest (Moto G4 - DSL) 完成的測試網站,比較早期提示的前後差異

如何使用初期提示

若要善用「早期提示」,首先要找出成效最佳的到達網頁,也就是使用者造訪網站時通常最先開啟的網頁。這可能會是首頁或熱門產品資訊頁面,如果您有許多使用者來自其他網站,比起其他網頁,這些進入點的重要性高於其他網頁,這是因為 Early Hint 在使用者瀏覽您網站時的實用性下降 (也就是說,瀏覽器更有可能在第二次或第三次後續瀏覽時擁有所有需要的子資源)。此外,持續建立良好的第一印像也是個好主意!

您現在已經建立這份優先的到達網頁清單,下一步就是找出哪些來源或子資源適合使用 preconnectpreload 提示。通常,這些項目是影響重要使用者指標的來源和子資源,例如 Largest Contentful PaintFirst Contentful Paint。更具體來說,請尋找會妨礙顯示功能的子資源,例如同步 JavaScript、樣式表或甚至網路字型。同樣地,您也可以找出代管子資源的來源,為重要使用者指標帶來許多助益。

此外請注意,如果主要資源已使用 preconnectpreload,您可以將這些來源或資源視為早期提示的候選項目。詳情請參閱如何最佳化 LCP。不過,單純將 preconnectpreload 指令從 HTML 複製到早期提示可能不是最佳選擇

在 HTML 中使用這些元素時,通常需要使用 Preload Scanner 無法找到的 preconnectpreload 資源,例如原本之後才發現的字型或背景圖片。您無法取得 HTML,因此可能想改用 preconnect 存取重要網域,或是其他原本可能在 HTML 開頭發現的重要資源 preload,例如預先載入 main.cssapp.js。此外,並非所有瀏覽器都支援 preload 的早期提示—請參閱瀏覽器支援

第二步是盡可能降低在主要資源可能已過時或不再使用的資源或來源上使用早期提示的風險。舉例來說,經常更新或需要版本的資源 (例如 example.com/css/main.fa231e9c.css) 可能不是最佳選擇。請注意,這個問題並非僅適用於 Early Hints,而是適用於任何 preloadpreconnect 的任何來源。這是最適合使用自動化或範本功能時的問題。舉例來說,手動程序可能會導致 preload 與使用資源的實際 HTML 標記之間出現不相符的雜湊或版本網址。

舉例來說,請考量下列流程:

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

伺服器預測需要 main.abcd100.css,並使用早期提示建議預先載入該項目:

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">

一般來說,應使用相當穩定且大部分與主要資源結果無關的資源和來源。如有需要,您可以考慮將主要資源分成兩個部分:一個穩定部分,與早期提示搭配使用;在瀏覽器收到主要資源後,要擷取另一個動態的部分:

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

最後,在伺服器端找出支援 Early Hints 的瀏覽器傳送的主要資源要求,然後立即以 103 早期提示做出回應。在 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 Hint 傳送的指令會因瀏覽器而異:

預先連線支援:

瀏覽器支援

  • 103
  • 103
  • 120
  • 17

預先載入支援:

瀏覽器支援

  • 103
  • 103
  • 123
  • x

Chrome 開發人員工具也提供 103 早期提示支援,且您可以在文件資源中查看 Link 標頭:

顯示「早期提示」標頭的網路面板
早期提示 Link 標頭會顯示在 Chrome 開發人員工具中。

請注意,如要使用 Early Hints 資源,請勿在開發人員工具中固定 Disable cache,因為 Early Hints 會使用瀏覽器快取。預先載入的資源中,發起者會顯示為 early-hints大小則顯示為 (Disk cache)

顯示早期提示啟動者的網路面板
早期提示資源具有 early-hints 啟動工具,並且是從磁碟快取載入。

您也必須使用信任的憑證才能進行 HTTPS 測試。

Firefox (自 v126 版起) 並未在開發人員工具中明確支援 103 早期提示,但使用早期提示載入的資源不會顯示 HTTP 標頭資訊,這是先前透過「早期提示」載入的指標。

伺服器支援

以下摘要說明熱門的開放原始碼軟體 HTTP 伺服器軟體對早期提示的支援等級:

以更輕鬆的方式啟用早期提示

如果您使用下列任一 CDN 或平台,可能不需要手動導入早期提示。請參閱解決方案供應商的線上說明文件,瞭解對方是否支援早期提示。您也可以參考以下清單 (僅列舉部分內容):

如何避免用戶端不支援 Early 提示

雖然 100 範圍內的資訊 HTTP 回應屬於 HTTP 標準,但部分舊版用戶端或漫遊器可能難以應對這些挑戰,因為在 103 早期提示推出前,它們很少用於一般網路瀏覽。

只在回應傳送 sec-fetch-mode: navigate HTTP 要求標頭的用戶端時,才發出 103 早期提示,可確保只將這類提示傳送給知道等待後續回應的新版用戶端。此外,由於只有瀏覽要求才支援早期提示 (請參閱目前的限制),因此這有額外的好處,就是您不用再傳送不必要的要求給其他要求。

此外,建議盡早透過 HTTP/2 或 HTTP/3 連線傳送早期提示,且大部分瀏覽器只會透過這些通訊協定接收提示。

進階模式

如果您已在主要到達網頁上全面採用「早期提示」功能,並找到更多商機,不妨試試以下進階模式。

對於一般使用者歷程中「第 n」nth頁要求的訪客,您可能需要調整「早期提示」對網頁中較低或更深的內容的回應,也就是對優先順序較低的資源使用「早期提示」功能。我們建議將重點放在高優先順序、禁止轉譯的子資源或來源,因此聽起來可能不符合直覺。然而,在訪客瀏覽內容一段時間後,他們的瀏覽器很可能已具備所有重要資源。接著,您就可以將注意力轉移到優先順序較低的資源上。舉例來說,這可能表示使用「早期提示」載入產品圖片,或是只用在較不常見的使用者互動時所需的其他 JS/CSS。

目前限制

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

  • 僅適用於導覽要求,也就是頂層文件的主要資源。
  • 僅支援 preconnectpreload (亦即不支援 prefetch)。
  • 早期提示在最終回應上接著跨來源重新導向,將導致 Chrome 捨棄使用 Early Hints 取得的資源和連線。
  • 使用「早期提示」預先載入的資源會儲存在 HTTP 快取中,之後再由網頁擷取。因此,只有可快取的資源可以透過早期提示預先載入,否則系統會重複擷取資源 (早期提示可能會重複擷取一次,再由文件再次擷取)。在 Chrome 中,系統會針對不受信任的 HTTPS 憑證停用 HTTP 快取,即使繼續載入網頁也是如此。

其他瀏覽器也有類似的限制,且如前所述,有些瀏覽器會進一步將 103 個早期提示限制為 preconnect

後續步驟

我們可能會依社區意願,以下列功能強化「早期提示」實作:

  • 使用記憶體快取 (而非 HTTP 快取) 無法快取的資源的早期提示。
  • 針對子資源要求傳送早期提示。
  • 在 iframe 主要資源要求上傳送早期提示。
  • 早期提示支援預先擷取。

我們歡迎提供意見,協助您決定要優先處理的事項,以及如何進一步改善早期提示。

與 H2/Push 的關係

如果您熟悉已淘汰的 HTTP2/推送功能,可能會想知道早期提示的差異。雖然 Early Hints 需要對瀏覽器來回往返,才能開始擷取重要的子資源,不過如果使用 HTTP2/Push,伺服器就能開始推送子資源,以及回應。雖然這聽起來令人驚豔,但卻引發了重大結構上的缺點:透過 HTTP2/Push 非常難以避免推送瀏覽器既有的子資源。這種「過度推送」效應導致網路頻寬的使用效率降低,大幅降低了效能方面的效益。整體而言,Chrome 資料顯示,HTTP2/Push 確實是網路效能下降的淨利。

相反地,Early Hints 實際上的成效較佳,因為它結合了傳送初步回應的功能,還結合了提示,讓瀏覽器負責擷取或連線至實際需求。雖然 Early Hints 並未涵蓋 HTTP2/Push 理論上可以解決的所有用途,但我們認為 Early Hints 是更實用的加快瀏覽速度解決方案。

Pierre Bamin 提供的縮圖。