迁移到用户代理客户端提示

将网站从依赖于用户代理字符串迁移到 新的用户代理客户端提示。

用户代理 字符串是 大量的被动数字“指纹”收集 呈现方式 而且难以处理然而,还有各种有效的 收集和处理用户代理数据的原因,因此我们需要 找到更好的解决方案。用户代理客户端提示同时提供了两种明确的方法 来声明您需要用户代理数据和方法,以便在 易于使用的格式。

本文将逐步介绍如何审核您对用户代理数据的访问权限,以及 将用户代理字符串的使用迁移到用户代理客户端提示。

审核用户代理数据的收集和使用

与任何形式的数据收集一样,您应始终清楚自己为何 正在收集信息无论您是否 就是了解您在何处以及为什么使用用户代理数据。

如果您不知道是否或在何处使用用户代理数据,请考虑在 使用 navigator.userAgent 的前端代码,以及用于 使用 User-Agent HTTP 标头。您还应检查前端代码 使用已弃用的功能,例如 navigator.platformnavigator.appVersion

从功能的角度来看,需要考虑你在代码中的任何位置 录制或处理内容:

  • 浏览器名称或版本
  • 操作系统名称或版本
  • 设备品牌或型号
  • CPU 类型、架构或位数(例如 64 位)

您也很可能在使用第三方库或服务 处理用户代理。在这种情况下,请检查它们是否更新为 支持用户代理客户端提示。

是否只使用基本的用户代理数据?

默认的用户代理客户端提示集包括:

  • Sec-CH-UA:浏览器名称和主要/重要版本
  • Sec-CH-UA-Mobile:表示移动设备的布尔值
  • Sec-CH-UA-Platform:操作系统名称 <ph type="x-smartling-placeholder">
      </ph>
    • 请注意,规范中对此进行了更新,并将在 Chrome 以及其他基于 Chromium 的浏览器。

建议的用户代理字符串的简化版本也将保留 以向后兼容的方式处理这些基本信息例如,将 Chrome/90.0.4430.85,则字符串将包含 Chrome/90.0.0.0

如果您只检查浏览器名称、主要版本 那么您的代码将继续有效,虽然您可能 以查看弃用警告。

虽然您可以也应该迁移到用户代理客户端提示,但您的旧版 API 代码或资源限制阻止它。模型中 以这种向后兼容的方式输入用户代理字符串 虽然现有代码收到的信息不太详细, 基本功能

策略:按需客户端 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 在 Google Cloud 上托管资源, https://cdn.site,可返回针对特定设备优化的资源。 https://blog.site可以请求 Sec-CH-UA-Model 提示,但需要 使用 Permissions-Policy 将其明确委托给 https://cdn.site。 标头。Clients Hints(客户端提示)中提供了政策控制提示的列表。 基础设施 草稿

🇦?️ 在将提示委托给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 属性会替换符合以下条件的所有 Accept-CH 标头: widget.site 可能会自行发送,因此请确保您已指定 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

这会产生第一个请求的重试开销,但是 实施成本相对较低。发送额外的标头和浏览器 将完成其余工作。

对于需要更多提示的情况 首次网页加载时,Client Hints Reliability 提案 布置一条路线,以在连接级设置中指定提示。这个 使用应用程序层协议 对 TLS 的 Settings(ALPS) 扩展 1.3 以在 HTTP/2 和 HTTP/3 连接上实现提示提前传递。这个 目前仍处于早期阶段,但如果您积极管理自己的 TLS 和 连接设置,那么这正是贡献内容的理想时机。

策略:旧版支持

您的网站上可能存在旧版或第三方代码,具体取决于 navigator.userAgent,包括用户代理字符串中将被触发 。从长远来看,您应计划改用等效项 navigator.userAgentData 调用,但有临时解决方案。

UA-CH retrofill 是 这个库可让您使用新字符串覆盖 navigator.userAgent, 根据请求的 navigator.userAgentData 值构建而成。

例如,此代码会生成一个用户代理字符串, 包含“model”提示:

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 罗恰 来源:Unsplash