遷移至使用者代理程式用戶端提示

從依賴使用者代理程式字串,改為使用新的 User-Agent Client Hints,以便遷移網站的策略。

User-Agent 字串是瀏覽器中重要的被動指紋記錄途徑,且難以處理。不過,收集和處理使用者代理程式資料有各種正當理由,因此我們需要的是更佳解決方案。使用者代理程式 Client Hints 提供明確的方式,讓您宣告使用者代理程式資料的需求,以及以易於使用的格式傳回資料的方法。

本文將逐步說明如何稽核您對使用者代理程式資料的存取權,以及將使用者代理程式字串用法遷移至使用者代理程式用戶端提示。

無論收集哪種形式的資料,您都應清楚瞭解收集資料的原因。無論您是否要採取任何行動,第一步都是瞭解使用者代理程式資料的使用位置和原因。

如果您不知道使用者代理程式資料是否使用或位於何處,請考慮在前端程式碼搜尋 navigator.userAgent 和後端程式碼,以便使用 User-Agent HTTP 標頭。您也應檢查前端程式碼,確認是否使用已淘汰的功能,例如 navigator.platformnavigator.appVersion

從功能性的觀點來看,思考您在程式碼中記錄或處理的任一處:

  • 瀏覽器名稱或版本
  • 作業系統名稱或版本
  • 裝置廠牌或型號
  • CPU 類型、架構或位元數 (例如 64 位元)

也可能是使用第三方程式庫或服務來處理使用者代理程式。在這種情況下,請確認他們是否會更新以支援 User-Agent Client Hints。

您是否只使用基本使用者代理程式資料?

預設的 User-Agent Client Hints 組合包括:

  • Sec-CH-UA:瀏覽器名稱和主要/重要版本
  • Sec-CH-UA-Mobile:代表行動裝置的布林值
  • Sec-CH-UA-Platform:作業系統名稱
    • 請注意,這項功能已在規格中更新,並會很快在 Chrome 和其他採用 Chromium 的瀏覽器中反映。

我們提議的簡化版使用者代理程式字串,也會以回溯相容的方式保留這些基本資訊。例如,字串會包含 Chrome/90.0.0.0,而非 Chrome/90.0.4430.85

如果您只檢查瀏覽器名稱、主要版本或作業系統的使用者代理程式字串,程式碼仍會繼續運作,但您可能會看到淘汰警告。

雖然您可以且應該遷移至「使用者代理程式用戶端提示」,但可能仍有舊版程式碼或資源限制導致這種情況。以這種向後相容的方式減少使用者代理程式字串中的資訊,目的是確保現有程式碼雖然會接收較少詳細資訊,但仍應保留基本功能。

策略:按需用戶端 JavaScript API

如果您目前使用 navigator.userAgent,請先轉換為優先使用 navigator.userAgentData,再改回剖析使用者代理程式字串。

if (navigator.userAgentData) {
  // use new hints
} else {
  // fall back to user-agent string parsing
}

如果您要檢查行動裝置或電腦,請使用布林值 mobile 值:

const isMobile = navigator.userAgentData.mobile;

userAgentData.brands 是包含 brandversion 屬性的物件陣列,瀏覽器可列出與這些品牌的相容性。您可以做為陣列直接存取,也可以使用 some() 呼叫檢查特定項目是否存在:

function isCompatible(item) {
  // In real life you most likely have more complex rules here
  return ['Chromium', 'Google Chrome', 'NewBrowser'].includes(item.brand);
}
if (navigator.userAgentData.brands.some(isCompatible)) {
  // browser reports as compatible
}

如果您需要其中一個更詳細的資訊完整使用者代理程式值,就需要指定該值,並在傳回的 Promise 中檢查結果:

navigator.userAgentData.getHighEntropyValues(['model'])
  .then(ua => {
    // requested hints available as attributes
    const model = ua.model
  });

如果您想從伺服器端處理作業改為用戶端端處理作業,也可以採用這項策略。JavaScript API 不需要存取 HTTP 要求標頭,因此您隨時可以要求使用者代理程式值。

策略:靜態伺服器端標頭

如果您在伺服器上使用 User-Agent 要求標頭,且您對該資料的需求在整個網站中相對一致,則可以在回應中將所需的用戶端提示指定為靜態集合。這是相對簡單的方法,因為您通常只需要在一個位置進行設定。舉例來說,如果您已在網路伺服器設定中加入標頭、代管設定,或是網站所用架構或平台的頂層設定,就可能會在其中找到這個標頭。

如果您要根據使用者代理程式資料轉換或自訂回應,不妨考慮採用這項策略。

瀏覽器或其他用戶端可能會選擇提供不同的預設提示,因此建議您一併指定所有必要的內容,即使這些內容通常會在預設情況下提供。

舉例來說,目前的 Chrome 預設值會顯示為:

⬇️ 回應標頭

Accept-CH: Sec-CH-UA-Mobile, Sec-CH-UA-Platform, Sec-CH-UA

如果您也想在回應中收到裝置型號,請傳送:

⬇️ 回應標頭

Accept-CH: Sec-CH-UA-Mobile, Sec-CH-UA-Model, Sec-CH-UA-Platform, Sec-CH-UA

在伺服器端處理這項作業時,您應先檢查是否已傳送所需的 Sec-CH-UA 標頭,然後在無法使用時改為使用 User-Agent 標頭剖析。

策略:將提示委派給跨來源要求

如果您要求跨來源或跨網站子資源,且要求在要求中傳送 User-Agent Client Hints,則必須使用權限政策明確指定所需的提示。

舉例來說,假設 https://blog.site 代管 https://cdn.site 上的資源,可傳回針對特定裝置最佳化的資源。https://blog.site 可以要求 Sec-CH-UA-Model 提示,但需要使用 Permissions-Policy 標頭明確將其委派給 https://cdn.site。您可以在 Client Hints Infrastructure 草稿中,查看政策控管提示清單

⬇️ blog.site 委派提示的回應

Accept-CH: Sec-CH-UA-Model
Permissions-Policy: ch-ua-model=(self "https://cdn.site")

⬆️ 對 cdn.site 子資源提出要求時,請納入委派提示

Sec-CH-UA-Model: "Pixel 5"

您可以為多個來源指定多個提示,而不僅限於 ch-ua 範圍:

⬇️ blog.site 將多個提示委派給多個來源的回應

Accept-CH: Sec-CH-UA-Model, DPR
Permissions-Policy: ch-ua-model=(self "https://cdn.site"),
                    ch-dpr=(self "https://cdn.site" "https://img.site")

策略:將提示委派給 iframe

跨來源 iframe 的運作方式與跨來源資源類似,但您必須在 allow 屬性中指定要委派的提示。

⬇️ blog.site 的回覆

Accept-CH: Sec-CH-UA-Model

↪️「blog.site」的 HTML

<iframe src="https://widget.site" allow="ch-ua-model"></iframe>

⬆️ widget.site收到的請款要求

Sec-CH-UA-Model: "Pixel 5"

iframe 中的 allow 屬性會覆寫 widget.site 可能自行傳送的任何 Accept-CH 標頭,因此請務必指定 iframe 網站所需的所有內容。

策略:動態伺服器端提示

如果您在使用者歷程的特定部分需要比網站其他部分更多的提示選項,可以選擇按需要求這些提示,而不是在整個網站中靜態顯示。這個管理方式比較複雜,但如果您已為個別路徑設定不同的標頭,可能可行。

這裡的重點是,每個 Accept-CH 標頭的例項都會有效覆寫現有的集合。因此,如果您要動態設定標頭,則每個網頁都必須要求所需的完整提示集。

舉例來說,您可能會在網站上提供一個區段,其中的圖示和控制項會根據使用者的作業系統而有所不同。為此,您可能需要額外提取 Sec-CH-UA-Platform-Version,以便提供適當的子資源。

⬇️ /blog 的回應標頭

Accept-CH: Sec-CH-UA-Mobile, Sec-CH-UA-Platform, Sec-CH-UA

⬇️ 「/app」的回應標頭

Accept-CH: Sec-CH-UA-Mobile, Sec-CH-UA-Platform, Sec-CH-UA-Platform-Version, Sec-CH-UA

策略:在首次要求時需要伺服器端提示

在某些情況下,您可能需要在首次要求中提供的預設提示以外的內容,但這種情況可能很少見,因此請務必查看原因。

第一個要求真正是指該瀏覽工作階段所傳送的第一個頂層要求。預設的提示組合包含瀏覽器名稱 (含主要版本)、平台和行動指標。因此,這裡的問題是,您是否需要在初始頁面載入時提供擴充資料?

如要取得第一項要求的額外提示,有兩種方法。首先,您可以使用 Critical-CH 標頭。這個標頭的格式與 Accept-CH 相同,但會告知瀏覽器,如果第一次傳送的標頭未附上重要提示,瀏覽器應立即重試要求。

⬆️ 初始要求

[With default headers]

⬇️ 回應標頭

Accept-CH: Sec-CH-UA-Model
Critical-CH: Sec-CH-UA-Model

🔃? 瀏覽器會使用額外標頭重試初始要求

[With default headers + …]
Sec-CH-UA-Model: Pixel 5

這會導致在第一個要求上重試的額外負擔,但實作成本相對較低。您只要傳送額外的標頭,瀏覽器就會完成其他步驟。

如果您確實需要在首次載入網頁時顯示額外的提示,用戶端提示可靠性提案會提供路徑,讓您在連線層級設定中指定提示。這會使用傳輸層安全標準 (TLS) 1.3 的應用程式層通訊協定設定 (ALPS) 擴充功能,以便提前傳遞 HTTP/2 和 HTTP/3 連線的提示。這項功能仍處於初期階段,但如果您積極管理自己的 TLS 和連線設定,現在正是貢獻心力的最佳時機。

策略:舊版支援

網站上可能有舊版或第三方程式碼依附於 navigator.userAgent,包括將減少的使用者代理程式字串部分。建議您長期規劃移至對等的 navigator.userAgentData 呼叫,但有暫時性的解決方案。

UA-CH 回溯填充是小型程式庫,可讓您使用從要求的 navigator.userAgentData 值建立的新字串,覆寫 navigator.userAgent

舉例來說,以下程式碼會產生使用者代理程式字串,以及「模型」提示:

import { overrideUserAgentUsingClientHints } from './uach-retrofill.js';
overrideUserAgentUsingClientHints(['model'])
  .then(() => { console.log(navigator.userAgent); });

產生的字串會顯示 Pixel 5 模型,但由於未要求 uaFullVersion 提示,因此仍會顯示縮減的 92.0.0.0

Mozilla/5.0 (Linux; Android 10.0; Pixel 5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.0.0 Mobile Safari/537.36

其他支援

如果這些策略不適用於您的用途,請在 privacy-sandbox-dev-support 存放區中發起討論,我們可以一起探討您的問題。

相片來源:Unsplash 上的 Ricardo Rocha