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

從依賴使用者代理程式字串,改為使用新的 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

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

雖然您可以且應改用 User-Agent Client Hints,但您可能會遇到舊版程式碼或資源限制,導致無法改用。以這種向後相容的方式減少使用者代理程式字串中的資訊,目的是確保現有程式碼雖然會接收較少詳細資訊,但仍應保留基本功能。

策略:按需用戶端 JavaScript API

如果您目前使用 navigator.userAgent,請改為優先使用 navigator.userAgentData,再改回剖析 user-agent 字串。

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.sitehttps://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

舉例來說,此程式碼會產生使用者代理程式字串,並額外加入「model」提示:

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