从零手写一个 UA 解析工具:我用 AI 辅助开发,踩了这些坑

背景

最近在整理开发日志分析流程时,经常需要从 User-Agent 字符串中快速判断用户使用的是哪个浏览器、什么操作系统。虽然网上有一堆现成的 UA 解析库(比如 ua-parser-js),但每次都要引入一个完整的 npm 包,就为了解析一个字符串,总觉得有点杀鸡用牛刀。而且有些在线工具需要把 UA 上传到服务器,涉及隐私问题,不太放心。

于是我想,不如自己写一个纯前端的 UA 解析工具,所有逻辑都在浏览器本地完成,不上传任何数据。正好最近在尝试用 AI 辅助编程,就决定用它来试试水。

传统方式的痛点

先说说为什么不用现成的库:

  1. 体积问题 :ua-parser-js 压缩后也有 20KB+,对于一个小工具来说太重了
  2. 依赖管理 :引入 npm 包意味着要维护 package.json、node_modules,对于单文件工具来说有点过
  3. 隐私考虑:很多在线 UA 解析工具需要把 UA 字符串发送到服务器,这在处理内部系统日志时是个隐患
  4. 过度设计:我需要解析的字段其实不多------浏览器名称/版本、引擎、OS、设备类型,完全可以用正则搞定

和 AI 协作的开发过程

第一轮:给需求,拿初版

我用的 Claude,第一次 prompt 大概是这样:

写一个单文件 HTML 工具,解析 User-Agent 字符串。功能要求:自动检测当前浏览器 UA、支持手动输入、展示浏览器/引擎/OS/设备类型、内置常见 UA 示例、支持中英文切换、深色模式。

AI 很快给出了一个完整的单文件 HTML,结构清晰,i18n 机制也做得不错。但第一版有个明显问题------解析逻辑太简单了:

javascript 复制代码
// AI 第一版的部分代码
if (ua.includes("Chrome")) {
  browserName = "Chrome";
}

这就有个大坑:Edge 的 UA 里也包含 "Chrome" 字样,Safari 的 UA 里也包含 "Chrome" 和 "Safari" 字样。如果按这个逻辑,Edge 会被识别成 Chrome,这显然不行。

第二轮:指出问题,要求改进

我告诉 AI:"Edge 的 UA 是 Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36 Edg/120.0.0.0,你的解析会把 Edge 识别成 Chrome,需要调整匹配顺序。"

AI 改进后的逻辑用了优先级数组:

javascript 复制代码
var browsers = [
  [/Edge\/([\d.]+)/, 'Edge'],
  [/Edg\/([\d.]+)/, 'Edge'],
  [/OPR\/([\d.]+)/, 'Opera'],
  [/SamsungBrowser\/([\d.]+)/, 'Samsung Internet'],
  [/Firefox\/([\d.]+)/, 'Firefox'],
  [/Version\/([\d.]+).*Safari/, 'Safari'],
  [/Chrome\/([\d.]+)/, 'Chrome']
];

这个方案很聪明:先匹配更具体的标识(Edge、OPR),最后才匹配 Chrome。因为 Edg/ 出现的优先级高于 Chrome/,所以能正确识别 Edge。

第三轮:处理"伪装"问题

还有一个经典坑:Chrome 的 UA 里包含 Safari/537.36,如果直接匹配 Safari 关键字,会把 Chrome 识别成 Safari。AI 用了 Version/[\d.]+.*Safari 这个模式,因为真正的 Safari 会有 Version/17.1 Safari/605.1.15 这种格式,而 Chrome 里只有 Safari/537.36 没有 Version/ 前缀。

这个细节我觉得 AI 处理得不错,相当于提前预判了"伪装"的情况。

第四轮:补充边界情况

我发现 AI 生成的代码对爬虫的识别不够全面。原来的代码只匹配了 Googlebot,但实际场景中还有 Bingbot、Baiduspider、curl、Postman 等。我让 AI 补充了这些:

javascript 复制代码
if (/bot|crawl|spider|slurp|bingpreview|facebookexternalhit|twitterbot|postman|curl|wget|python|java|go-http-client|node-fetch|axios/i.test(ua)) {
  r.isBot = true;
  var bm = ua.match(/(Googlebot|Bingbot|Slurp|DuckDuckBot|Baiduspider|YandexBot|facebookexternalhit|Twitterbot|Postman|curl|Wget|Python|Java|python-requests)/i);
  // ...
}

技术实现细节

解析顺序

UA 解析的核心是顺序敏感。我最终确定的解析顺序是:

  1. 先判断是不是 Bot/爬虫
  2. 再识别渲染引擎(Gecko/Blink/WebKit/Trident)
  3. 然后识别浏览器(优先级从高到低)
  4. 最后识别操作系统和设备类型

这个顺序是有讲究的:如果先识别浏览器再识别引擎,可能会因为 Chrome 和 Edge 共享 Blink 引擎而混淆。

设备类型判断

设备类型判断有个小技巧:

javascript 复制代码
if (/iPad/.test(ua)) r.deviceType = 'tablet';
else if (/Mobile|iPhone|Android.*Mobile/.test(ua)) r.deviceType = 'mobile';
else if (/Android/.test(ua) && !/Mobile/.test(ua)) r.deviceType = 'tablet';
else r.deviceType = 'desktop';

注意第三个条件:Android 平板(比如 Pixel Tablet)的 UA 里没有 Mobile 字样,所以需要单独处理。这也是 AI 帮我发现的边界情况。

复制功能的降级处理

现代浏览器都支持 navigator.clipboard,但为了兼容性,我加了一个 fallback:

javascript 复制代码
function copyVal(el) {
  var text = el.textContent;
  if (!text) return;
  if (navigator.clipboard && navigator.clipboard.writeText) {
    navigator.clipboard.writeText(text)
      .then(() => setStatus('success', t('copied') + ': ' + text))
      .catch(() => fallbackCopy(text));
  } else {
    fallbackCopy(text);
  }
}

i18n 实现

没有用任何框架,就是一个简单的 key-value 映射:

javascript 复制代码
var I18N = {
  zh: { title: "User-Agent 解析", parse: "解析", /* ... */ },
  en: { title: "User-Agent Parser", parse: "Parse", /* ... */ }
};
var lang = detectLang();
var t = (key) => I18N[lang][key] || key;

语言检测优先级:URL 参数 ?lang=en > 浏览器语言 > 默认中文。

踩坑记录

坑 1:Safari 的 Version/ 前缀

一开始我直接用 /Safari\/([\d.]+)/ 匹配 Safari 版本,结果 Chrome 的 UA 里也有 Safari/537.36,版本号全乱了。后来改成 Version/[\d.]+.*Safari 才正确。

坑 2:Windows 版本识别

Windows NT 10.0 可能是 Windows 10 也可能是 Windows 11,因为 UA 里没有区分。我最终显示为 "Windows 10/11",算是诚实处理。

坑 3:AI 生成的代码有时"太聪明"

有次 AI 为了处理"伪装"情况,写了一个很复杂的正则嵌套,可读性极差。我让它简化了------毕竟这个工具的核心价值是快速、准确,不是展示正则技巧。

对 AI 辅助编程的感想

这次开发让我对 AI 辅助编程有了新的认识:

  1. AI 擅长搭骨架,但细节还得人盯:AI 生成的第一版代码能跑,但边界情况处理得很粗糙
  2. prompt 要具体:给 AI 示例 UA 字符串比说"处理各种浏览器"效果好得多
  3. 代码审查不能省:AI 生成的每一行代码都要过一遍,特别是正则表达式
  4. AI 是很好的代码评审员:我经常把写好的代码丢给它,让它找 bug 和优化空间

适用场景

这个工具适合以下场景:

  • 日志分析:快速判断访问者的浏览器和系统分布
  • 调试开发:验证自己的页面在不同 UA 下的表现
  • 爬虫识别:判断请求是真人还是 Bot
  • 技术分享:演示 UA 字符串的组成结构

总结

从需求提出到最终完成,整个过程大概花了一个下午。AI 帮我完成了 80% 的代码框架,我负责补充边界情况和测试验证。这种协作方式确实比纯手写高效,但前提是你得知道自己在做什么------AI 生成的代码,你得能看懂、能改、能测。

如果你也有 UA 解析的需求,可以直接体验我在线部署的版本:User-Agent 解析工具。纯前端实现,数据不会离开你的浏览器。

相关推荐
Agent世界12 小时前
用 CDP 做发布自动化:四道机器闸门与产物验收
前端·javascript
FungLeo12 小时前
成为全栈·Vue 管理后台篇·编辑器图片上传:从文件选择到文章附件关联
前端·vue.js·编辑器·markdown·文件上传·formdata·附件管理
某哈压力大13 小时前
SSH 突然 Connection reset?不是密钥坏了,是 OpenSSL 把 sshd 干趴了
前端·node.js·命令行
程序员大阳13 小时前
副队长ES6+教程(3)--解构赋值
前端·javascript·es6·赋值·解构
神膘护体小月半13 小时前
css - 元素背景图由 hover 触发,初次加载时闪动的解决办法
前端·javascript·css
程序员大阳13 小时前
副队长ES6+教程(2)--let 与 const
前端·javascript·es6·const·let·var
deli00714 小时前
写满 200GB 后 SSD 为什么掉到 95MB/s?SLC 缓存模型实测
前端
曦樂~15 小时前
【Web Development】03JavaScript 基础和事件
开发语言·前端·javascript
deli00715 小时前
HTTPS 的锁是怎么挂上的?TLS 1.3 握手 6 步实测
前端
程序员大阳15 小时前
副队长ES6+教程(1)--ES6+初识
前端·ecmascript·es6