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

將網站從依賴使用者代理程式字串遷移至新版 User-Agent Client Hints 的策略。

使用者代理程式字串是瀏覽器中重要的被動式數位指紋採集介面,且難以處理。不過,收集和處理使用者代理程式資料各有不同,因此需要採取更有效的解決方案。「使用者代理程式用戶端提示」提供了一種明確的方式,可讓您明確宣告對使用者代理程式資料和方法的需求,以方便使用的格式傳回資料。

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

稽核使用者代理程式資料的收集和使用方式

與任何形式的資料收集方式一樣,您應隨時瞭解收集資料的「原因」。無論您是否採取任何行動,第一步都是瞭解要使用使用者代理程式資料的位置和原因。

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

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

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

也可能是使用第三方程式庫或服務來處理使用者代理程式。在此情況下,請檢查更新是否為支援「使用者代理程式用戶端提示」。

您只能使用基本的使用者代理程式資料嗎?

預設的「使用者代理程式用戶端提示」包括:

我們提議的簡化版使用者代理程式字串,也會以回溯相容的方式保留這些基本資訊。例如,字串會包含 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 標頭剖析。

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

如果您要求在要求中傳送「使用者代理程式用戶端提示」,才能要求跨來源或跨網站子資源,則必須使用權限政策明確指定所需的提示。

舉例來說,假設 https://blog.site 代管 https://cdn.site 上的資源,可傳回針對特定裝置最佳化的資源。https://blog.site 可以要求 Sec-CH-UA-Model 提示,但需要使用 Permissions-Policy 標頭明確將其委派給 https://cdn.site。如需政策控制的提示清單,請參閱「用戶端提示基礎架構草稿

⬇️ 來自 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 retrofill 是一個小型程式庫,可讓您使用根據要求的 navigator.userAgentData 值所建構的新字串覆寫 navigator.userAgent

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

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

產生的字串會顯示 Pixel 5 模型,但仍會顯示較低的 92.0.0.0,因為未要求 uaFullVersion 提示:

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 存放區中發起討論,讓我們一起探索您的問題。

相片來源:Ricardo Rocha,發表於 Unsplash 網站上