Skip to content

一、整体思路

  • 优先用 UA-CH(User-Agent Client Hints):更隐私、可控,浏览器逐步冻结传统 UA 字符串的细节,官方鼓励迁移到 UA-CH。(WICG)
  • UA 兜底:当 UA-CH 不可用或信息不足,再解析 navigator.userAgent。(MDN Web Docs)
  • 能力优先:涉及 Passkeys/WebAuthn 时,尽量做“能力探测”而不是“品牌猜测”,例如探测平台验证器、条件式 UI 等。(MDN Web Docs)

二、分步实现

步骤 1:读取低熵 UA-CH(无需权限)

ts
// 复杂逻辑:优先读取 UA-CH 的低熵字段,获取平台与品牌
const uaData = (navigator as any).userAgentData;
const platform = uaData?.platform ?? ""; // 例:'Windows' | 'macOS' | 'Android' | 'iOS' ...
const brands = uaData?.brands ?? []; // 例:[ {brand:'Chromium', version:'140'}, {brand:'Microsoft Edge', version:'140'} ]
  • platform:当前平台名称。
  • brands:浏览器“品牌”列表(Chromium/Chrome/Edge 等),常用于判断是否 Chromium 家族。 以上字段由 NavigatorUAData 暴露,属于 UA-CH 的“低熵”部分。(MDN Web Docs)

步骤 2:读取高熵 UA-CH(需显式请求)

ts
// 复杂逻辑:请求高熵字段,获取更细粒度的版本/架构/模式等
const high = uaData
  ? await uaData.getHighEntropyValues([
      "architecture", // CPU 架构:'x86' | 'arm' ...
      "bitness", // 位宽:'64' | '32'
      "model", // 设备型号(移动端常见)
      "platformVersion", // 平台版本:如 Windows 内核版本
      "uaFullVersion", // 浏览器完整版本号
      "fullVersionList", // 全量 brand+version 列表
      "wow64", // 是否 WOW64 兼容层
    ])
  : {};

这些字段由 NavigatorUAData.getHighEntropyValues() 一次性返回,便于做平台差异化或下载架构选择(如 32/64 位)。(MDN Web Docs)

常见用途举例:

  • bitness/architecture:选择下载 64 位或 32 位安装包。(MDN Web Docs)
  • platformVersion:区分 Windows 10 vs 11 的行为、样式或性能开关。(Microsoft Learn)
  • fullVersionList:更精确地判断浏览器及其完整版本。(MDN Web Docs)

步骤 3:UA 字符串兜底解析

ts
// 复杂逻辑:在 UA-CH 不可用时兜底解析 UA 字符串
const ua = navigator.userAgent; // 传统 UA,需注意已逐步“去细节化”
const isEdge = /\bEdg\/([\d.]+)/.test(ua); // Edge 使用 "Edg/..." 标记
const isChrome = /\bChrome\/([\d.]+)/.test(ua) && !isEdge;
const isSafari = /Safari\/[\d.]+$/.test(ua) && !isChrome && !isEdge;
  • Navigator.userAgent 是传统 UA 字符串,仍可用,但细节可能被“冻结”。(MDN Web Docs)
  • Edge 在 UA 中以 Edg/<version> 标记;不要只匹配 Edge。(MDN Web Docs)

步骤 4:WebAuthn/Passkeys 能力探测(推荐)

ts
// 复杂逻辑:是否存在“平台验证器”(本机指纹/面容/Windows Hello 等)
const uvpaa =
  await PublicKeyCredential.isUserVerifyingPlatformAuthenticatorAvailable();

// 复杂逻辑:是否支持“条件式 UI”(表单自动填充一键直登)
const canConditional = await(
  PublicKeyCredential as any
).isConditionalMediationAvailable?.();

// 复杂逻辑:未来可用:一次性查询浏览器 WebAuthn 能力集合
const caps = await(PublicKeyCredential as any).getClientCapabilities?.();
  • isUserVerifyingPlatformAuthenticatorAvailable():探测本机是否有“可用户验证”的平台验证器。(MDN Web Docs)
  • isConditionalMediationAvailable():探测是否支持 Conditional UI 登录体验。(MDN Web Docs)
  • getClientCapabilities():WebAuthn Level 3 引入的能力查询。(MDN Web Docs)

三、UA-CH 字段一览与用途

字段类型/示例作用与典型用法
platform"Windows" / "macOS" / "Android" / "iOS"粗粒度平台判断(低熵)。(MDN Web Docs)
brands[{brand:'Chromium',version:'140'}...]判断是否基于 Chromium、有哪些品牌标识(低熵)。(MDN Web Docs)
architecture"x86" / "arm"CPU 架构(高熵,需申请)。(MDN Web Docs)
bitness"64" / "32"选择 64/32 位资源(高熵)。(MDN Web Docs)
model"iPhone"设备型号(移动端常见,高熵)。(MDN Web Docs)
platformVersion"13.0.0"Windows 11 等版本区分(高熵)。(Microsoft Learn)
uaFullVersion"140.0.0.0"浏览器完整版本(高熵)。(MDN Web Docs)
fullVersionList[{brand:'Chromium',version:'140.0.0.0'}, ...]更精确识别品牌+版本(高熵)。(MDN Web Docs)
wow64true/false是否运行在 WOW64 兼容层(高熵)。(MDN Web Docs)

注意:UA-CH 的“高熵”字段需要通过 JS 显式请求或服务端通过 Accept-CH 提示,浏览器才会提供。(MDN Web Docs)


四、最简代码示例

仅演示关键探测点;复杂逻辑处已在上一行写注释。

ts
// 复杂逻辑:综合 UA-CH 与 UA,返回 { platform, isChromium, isEdge, isSafari, versions }
export async function detectRuntime() {
  const navAny = navigator as any;
  const uaData = navAny.userAgentData;
  const ua = navigator.userAgent;

  let platform = "";
  let brands: Array<{ brand: string; version: string }> = [];
  let fullVersionList: Array<{ brand: string; version: string }> = [];

  if (uaData) {
    platform = uaData.platform ?? "";
    brands = uaData.brands ?? [];
    try {
      // 复杂逻辑:尽量取到完整版本列表
      const high = await uaData.getHighEntropyValues(["fullVersionList"]);
      fullVersionList = high.fullVersionList ?? [];
    } catch {}
  }

  // 复杂逻辑:判断 Chromium 家族(从 brands 与 UA 双通道)
  const brandsText = brands.map((b) => b.brand).join(" ");
  const isChromium =
    /Chrom(e|ium)|Google Chrome|Microsoft Edge|Opera|OPR|Brave/i.test(
      brandsText
    ) || /\b(Chrome|Chromium|Edg|OPR|Brave)\b/i.test(ua);

  // 复杂逻辑:Edge、Chrome、Safari 的基本判断
  const isEdge = /\bEdg\/[\d.]+/.test(ua);
  const isChrome = /\bChrome\/[\d.]+/.test(ua) && !isEdge;
  const isSafari = /Safari\/[\d.]+$/.test(ua) && !isChrome && !isEdge;

  return {
    platform,
    isChromium,
    isEdge,
    isSafari,
    versions: { brands, fullVersionList },
  };
}

// 复杂逻辑:WebAuthn 能力探测(平台验证器 & 条件式 UI)
export async function detectWebAuthn() {
  const uvpaa =
    await PublicKeyCredential.isUserVerifyingPlatformAuthenticatorAvailable();
  const canConditional = await (
    PublicKeyCredential as any
  ).isConditionalMediationAvailable?.();
  const caps = await (PublicKeyCredential as any)
    .getClientCapabilities?.()
    .catch(() => undefined);
  return { uvpaa, canConditional, caps };
}
  • UA-CH 的 fullVersionList 提供比 UA 更稳的“品牌+完整版本”。(MDN Web Docs)
  • WebAuthn 的三个静态探测方法可用于决定是否展示 条件式 UI、是否允许平台凭据登录等。(MDN Web Docs)

五、UA 字符串逐段拆解(实战)

给定 UA:

Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36
(KHTML, like Gecko) Chrome/140.0.0.0 Safari/537.36 Edg/140.0.0.0

逐段含义:

  • Mozilla/5.0:历史兼容标记,表示“与 Mozilla 兼容”。如今几乎所有浏览器都会带上它。(Stack Overflow)
  • (Windows NT 10.0; Win64; x64):平台信息(Windows,内核版本 10.0,64 位)。
  • AppleWebKit/537.36:渲染引擎历史标识(WebKit/Blink 系都常带此段,出于兼容)。(MDN Web Docs)
  • (KHTML, like Gecko):历史说明“像 Gecko 一样”,早期对站点嗅探的兼容产物。
  • Chrome/140.0.0.0Chromium/Chrome 基因的版本号片段。
  • Safari/537.36:同样是历史兼容字段,非真正 Safari 也会带。(MDN Web Docs)
  • Edg/140.0.0.0Microsoft Edge 的明确标记(注意是 Edg/ 而非 Edge/)。(MDN Web Docs)

结论:这串 UA 同时包含 WebKit/Chrome/Safari 的历史兼容片段,真正决定“它是 Edge”的是结尾的 Edg/140...。这就是你看到“怎么什么都有”的原因:为了兼容旧站点的 UA 嗅探,浏览器刻意保留了多段看似“矛盾”的标识。(MDN Web Docs)


六、最佳实践与注意事项

  1. 能用 UA-CH 就别靠 UA:UA 正在“去细节化/冻结”,准确性和可持续性不如 UA-CH。(MDN Web Docs)
  2. WebAuthn 以“能力探测”为先:优先根据 uvpaa/conditional 等能力决定登录体验,而非“浏览器品牌”。(MDN Web Docs)
  3. 确定“供应商/来源”时用 AAGUID:注册阶段记录 AAGUID(如需),比 UA/UA-CH 更可靠。(web.dev)

七、快速参考

  • UA-CH 规范与 API:MDN、WICG 文档与 Chrome 指南。(MDN Web Docs)
  • UA 基础与 Edge 标记:MDN UA 参考、Microsoft 文档。(MDN Web Docs)
  • WebAuthn 能力:MDN 与 WebAuthn Level 3。(MDN Web Docs)

有了上述探测与解读框架,你就可以稳定地拿到平台/浏览器/能力信息,并在 Passkeys 场景里用“能力优先”的策略,提供更一致的登录体验。

本站总访问