创见博客
请求中的 User-Agent 是什么:浏览器、爬虫与 AI Bot 如何表明身份
七崽爱吃小饼干2026/08/19阅读 1

先看一条浏览器发出的 HTTP 请求:

http
GET /articles/42 HTTP/1.1
Host: example.com
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/140.0.0.0 Safari/537.36
Accept: text/html,application/xhtml+xml
Accept-Language: zh-CN,zh;q=0.9

其中这一行就是通常所说的 UA:

http
User-Agent: Mozilla/5.0 ... Chrome/140.0.0.0 Safari/537.36

它由客户端放进请求头,用一段字符串描述“是谁在发请求”。浏览器会写入浏览器引擎、产品和操作系统等信息;命令行工具、移动 App、搜索爬虫和 AI Bot 也可以写入自己的名称。

但 UA 只是客户端的一段自我介绍,不是身份证。服务端可以读取它,客户端也可以随意修改它。理解这个边界,才能正确使用 UA。

UA 到底表示什么

User Agent 原本指代代表用户访问网络资源的软件。Chrome、Safari、微信 WebView、curl、搜索引擎爬虫,甚至后端服务调用方,都可以是 User Agent。

HTTP 中的 User-Agent 请求头则是这个客户端主动提交的标识。例如:

text
curl/8.7.1
text
PostmanRuntime/7.44.1
text
MyApp/3.2.0 (iOS 18.5; iPhone)

服务端在 Node.js 中可以直接读取:

ts
export async function GET(request: Request) {
  const userAgent = request.headers.get('user-agent') ?? '';

  return Response.json({ userAgent });
}

在 Nginx 日志中,UA 通常来自 $http_user_agent:

nginx
log_format main '$remote_addr "$request" $status "$http_user_agent"';
access_log /var/log/nginx/access.log main;

因此,浏览器开发者工具里看到的是客户端准备发送的 UA,服务端访问日志里记录的则是服务端实际收到的 UA。请求经过 CDN、网关或反向代理时,还要确认中间层有没有删除、改写或另外保存原始值。

为什么一条浏览器 UA 看起来这么乱

下面是一条典型的 Chromium UA:

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

它看起来同时包含 Mozilla、AppleWebKit、Chrome 和 Safari,并不代表用户同时安装了四个浏览器。这主要是历史兼容的结果。

早期网站会根据 UA 判断浏览器并决定是否返回某项功能。新浏览器为了获得原本只向主流浏览器开放的页面,会携带兼容标记。时间久了,UA 逐渐变成一条需要兼容旧规则的历史清单。

可以粗略理解为:

  • Mozilla/5.0:沿用至今的兼容标记,不代表当前浏览器就是 Firefox。
  • Windows NT 10.0; Win64; x64:平台和架构信息。
  • AppleWebKit/537.36:声明兼容 WebKit 风格的引擎标记。
  • KHTML, like Gecko:历史兼容信息。
  • Chrome/140.0.0.0:Chrome 产品及版本标记。
  • Safari/537.36:用于兼容部分 Safari 检测逻辑的标记。

所以不能用 ua.includes('Safari') 就判定 Safari,也不能看到 Mozilla 就判定 Firefox。生产环境需要使用维护中的 UA 解析库,并准备好无法识别的新客户端。

UA 有哪些实际作用

1. 兼容性处理

某些浏览器、WebView 或旧设备确实存在特定兼容问题。服务端可以根据 UA 返回降级页面,前端也可以临时绕过已知 Bug。

但优先级应该是:

text
特性检测 > 渐进增强 > UA 判断

例如,要判断浏览器是否支持某个 API,应直接检查能力:

ts
if ('IntersectionObserver' in window) {
  // 使用对应能力
} else {
  // 加载降级实现
}

UA 判断适合处理“某个已知版本实现有缺陷”之类的例外,不适合成为所有功能开关的基础。否则新浏览器、套壳浏览器和 UA 变化都可能导致误判。

2. 设备与页面适配

服务端有时需要在 HTML 生成前粗略判断移动端或桌面端,例如返回不同尺寸的图片、不同下载入口,或者为移动设备选择更轻的首屏内容。

ts
const isMobile = /Android|iPhone|Mobile/i.test(userAgent);

这种简单规则可以用于非关键优化,但不应承担精确设备识别。平板、折叠屏、桌面模式、WebView 和修改过的 UA 都会破坏“手机或电脑”的二分法。页面布局通常更适合交给 CSS Media Query 和响应式设计。

3. 数据分析与故障定位

UA 是访问日志的重要维度,可以用来回答:

  • 某次报错是否集中在 iOS WebView。
  • 新版本发布后,旧浏览器失败率是否上升。
  • 接口流量来自浏览器、App、脚本还是爬虫。
  • 某个异常请求是否使用了批量脚本工具。

日志分析时最好保存原始 UA,同时再生成浏览器、操作系统、设备类型等结构化字段。只保存解析结果会丢失信息,也不便于以后用新版规则重新分析。

4. 爬虫识别和流量治理

搜索引擎通常会在 UA 中声明自己的爬虫名称。例如 Googlebot 的 UA 中会出现 Googlebot/2.1。服务端可以据此统计抓取量、检查 SEO 页面是否正常返回,或对爬虫设置独立的限流和缓存策略。

ts
const crawlerPattern =
  /Googlebot|bingbot|GPTBot|OAI-SearchBot|ChatGPT-User|ClaudeBot|Claude-SearchBot|Claude-User|PerplexityBot/i;

const looksLikeCrawler = crawlerPattern.test(userAgent);

注意变量名是 looksLikeCrawler,而不是 isTrustedCrawler。这段代码只能说明 UA 看起来像爬虫,不能证明请求真的来自对应厂商。

5. API 客户端标识

自有 App、SDK 和后端服务也可以使用清晰的 UA,方便服务端排查版本问题:

http
User-Agent: Visionary-iOS/4.8.0 (iOS 18.5)
http
User-Agent: visionary-cli/1.6.2 node/22.17.0

这种标识非常适合可观测性,但仍然不能代替 Authorization、API Key、请求签名或 mTLS。UA 负责“方便识别”,认证信息负责“证明身份”。

爬虫会使用特殊请求头吗

合规爬虫通常会使用有辨识度的 UA,有时还会附带说明页面或联系方式:

text
Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)

它们并不一定拥有某个所有爬虫通用、且无法伪造的特殊请求头。大多数情况下,最明显的线索仍然是 User-Agent。

不同爬虫的行为大致分为三类:

类型常见 UA 表现目的
搜索引擎爬虫Googlebot、bingbot建立搜索索引
明确声明的内容爬虫产品名、Bot 名称、说明 URL聚合、监控、训练或其他自动抓取
伪装型爬虫模仿普通 Chrome、Safari绕过简单 UA 规则

使用 Playwright、Puppeteer 等真实浏览器内核的自动化程序,还可能自然带有接近普通浏览器的整套请求头。即使 UA 中没有 HeadlessChrome,它也不一定是真人访问。

因此,判断自动化流量时还会结合:

  • 来源 IP、ASN,以及厂商公布的 IP 段。
  • 正向和反向 DNS 验证。
  • Cookie、JavaScript 执行和会话连续性。
  • 请求频率、访问顺序、鼠标与页面行为。
  • Accept、Accept-Language、Referer、Sec-Fetch-* 等请求头是否合理。
  • TLS 和 HTTP 协议层指纹。

这些信号也不是单独使用就绝对可靠。实际风控通常是多信号评分,而不是一条正则表达式。

AI 爬虫的 UA 有什么不同

AI 服务不一定只使用一个 Bot。以 OpenAI 官方文档列出的标识为例,不同 UA 对应不同目的:

UA 标识主要用途
GPTBot抓取可能用于改进模型的内容
OAI-SearchBot支持搜索结果中的发现与展示
ChatGPT-User响应用户操作访问页面

Anthropic 也使用 ClaudeBot、Claude-SearchBot 和 Claude-User 区分训练抓取、搜索抓取与用户触发访问。

这说明“AI 爬虫”并不是一种单一流量。网站可能愿意让内容进入 AI 搜索并获得引用,但不希望它被训练爬虫采集;也可能允许用户主动让 AI 读取某个公开页面。策略应该按 Bot 和用途配置,而不是用 /AI|GPT|Claude/i 一刀切。

例如,可以在 robots.txt 中分别表达策略:

text
User-agent: GPTBot
Disallow: /

User-agent: OAI-SearchBot
Allow: /

User-agent: ChatGPT-User
Allow: /

这里有两个重要边界:

  1. robots.txt 是面向合规爬虫的抓取约定,不是访问控制。私密内容必须依靠登录鉴权,不能只写 Disallow。
  2. Bot 名称和策略可能变化,上线前应查阅厂商最新官方文档,不要永久复制一份来源不明的 UA 清单。

还有一个容易误解的例子:Google-Extended 是 robots.txt 中用于控制相关生成式 AI 使用方式的产品令牌,并没有独立的同名 HTTP User-Agent。不能假设每一个 robots.txt 令牌都会原样出现在请求头里。

为什么不能只靠 UA 判断可信爬虫

任何客户端都可以发送下面的请求:

bash
curl 'https://example.com/' \
  -H 'User-Agent: Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)'

如果服务端看到 Googlebot 就绕过登录、风控或付费墙,攻击者也能获得同样权限。UA 不能用于:

  • 鉴权或判断用户身份。
  • 绕过权限校验、验证码和支付限制。
  • 向所谓内部客户端返回密钥或未发布内容。
  • 无条件把高消耗接口开放给“友好爬虫”。

对支持来源验证的厂商,应把 UA 与官方 IP 段或 DNS 验证结合。Google 官方也明确提醒 UA 可以伪造,并提供了爬虫验证方法。

如果只是为公开页面选择更合适的缓存、记录统计或返回可访问的静态 HTML,UA 误判的安全影响较低,可以把它当作第一层信号。如果判断结果会改变权限,UA 就远远不够。

在 Chrome 中临时修改 UA

如果想验证网站对不同 UA 的处理逻辑,可以直接在 Chrome DevTools 中临时修改当前标签页发送的 User-Agent。

  1. 打开 Chrome DevTools。
  2. 点击右上角的更多选项,依次选择 More tools -> Network conditions。
  1. 在 User agent 区域取消勾选 Use browser default。
  2. 选择预设值或输入自定义 UA,例如 OAI-SearchBot,然后刷新页面使其生效。

这种方式适合调试 UA 识别、页面渲染、日志记录和爬虫策略。它通常只影响当前 DevTools 对应的标签页,并需要在调试期间保持 DevTools 打开。

还要注意,把 UA 改成 OAI-SearchBot 只代表请求头“声称”自己是该 Bot,并不会让请求来自 OpenAI 的官方 IP,也不会自动获得真实爬虫的 DNS、网络特征或访问权限。这正好说明了为什么服务端不能仅凭 UA 验证爬虫身份。

UA 正在被减少:Client Hints 是什么

传统 UA 暴露的信息越细,越容易参与浏览器指纹识别。与此同时,复杂字符串也让兼容规则越来越脆弱。Chromium 因此逐步减少传统 UA 中可用的细粒度信息,并提供 User-Agent Client Hints。

Chromium 请求中可能出现:

http
Sec-CH-UA: "Not=A?Brand";v="99", "Chromium";v="140", "Google Chrome";v="140"
Sec-CH-UA-Mobile: ?0
Sec-CH-UA-Platform: "macOS"

与一整条非结构化字符串相比,这些字段更容易解析。Sec-CH-UA 还可能故意包含一个看起来奇怪的品牌项,这是设计的一部分,业务代码不能默认列表中的每一项都是真实产品名。

服务端如果确实需要更高精度的信息,可以通过 Accept-CH 声明希望后续请求携带哪些提示:

http
Accept-CH: Sec-CH-UA-Platform-Version, Sec-CH-UA-Model

但 Client Hints 不是 UA 的全平台无缝替代品。它主要由 Chromium 系浏览器支持,部分高熵信息需要服务端请求,而且涉及缓存和隐私策略。实现时仍应遵循几个原则:

  • 能做特性检测,就不识别浏览器品牌。
  • 只请求业务真正需要的信息。
  • 不把 Client Hints 当作认证信息。
  • 使用相关字段生成不同响应时,正确设计 Vary 和 CDN 缓存键。
  • 对不支持 Client Hints 的客户端保留合理默认行为。

实际项目应该怎么处理 UA

可以按下面的顺序落地。

1. 先明确判断结果会影响什么

统计标签、调试信息和公开页面优化属于低风险用途;权限、价格、私密内容和风控放行属于高风险用途。后者不能只依赖 UA。

2. 保留原始值,再做结构化解析

日志中保存原始 UA,并额外记录解析后的浏览器、系统、设备类型和 Bot 类型。规则升级后,原始数据仍然可以重新计算。

3. 对未知客户端提供默认路径

不要建立“UA 不认识就拒绝”的白名单式兼容逻辑。新浏览器、隐私工具和内部客户端都可能没有进入现有规则库。

4. 把爬虫声明和身份验证分开

text
UA 命中 Bot 名称      -> 声明型爬虫
UA + 官方来源验证成功 -> 已验证爬虫

限流、缓存、日志和权限策略可以根据可信等级分别处理。

5. 定期维护 Bot 策略

搜索和 AI 厂商会新增、拆分或调整 Bot。维护一份包含用途、官方文档、验证方式、允许范围和更新时间的配置,比把长正则散落在业务代码中更可靠。

最后记住四句话

User-Agent 是客户端写入请求头的一段自我描述。

它适合兼容处理、数据分析、故障定位和爬虫初步分类。

正常浏览器、普通爬虫和 AI Bot 往往有不同 UA,但任意客户端都能伪造它。

因此,UA 可以回答“它声称自己是谁”,不能单独回答“它到底是谁”。

评论
0/100