bowser、platform 和 ua-parser-js 都是用于解析浏览器 User-Agent 字符串的 JavaScript 库,旨在帮助开发者识别用户的环境信息。bowser 专注于轻量级的浏览器版本检测,提供简洁的 API 来判断浏览器类型和版本。platform 是一个历史悠久的库,提供基本的操作系统和浏览器名称识别,但近年来维护频率较低。ua-parser-js 则是功能最全面的方案,支持解析浏览器、引擎、操作系统和设备详情,广泛用于需要精细环境识别的场景。
在前端架构中,准确识别用户环境是兼容性处理、数据分析和安全风控的基础。bowser、platform 和 ua-parser-js 是三个最常见的解决方案,但它们的設計理念和适用场景截然不同。本文将从核心 API、功能深度、安全性三个维度进行深度对比。
三个库的入口方式不同,这直接影响代码的可维护性和测试难度。
bowser 采用函数式链式调用,无状态设计,适合按需解析。
import bowser from 'bowser';
const ua = navigator.userAgent;
const parser = bowser.getParser(ua);
const browser = parser.getBrowser();
// 输出:{ name: 'Chrome', version: '91.0' }
platform 通常暴露一个全局对象,在浏览器端自动解析,Node.js 端需手动调用。
import platform from 'platform';
// 浏览器环境自动填充
console.log(platform.name);
// Node.js 环境需手动解析
const info = platform.parse(ua);
// 输出:{ name: 'Chrome', version: '91.0', os: ... }
ua-parser-js 采用类实例化模式,支持复用解析器实例,适合批量处理。
import UAParser from 'ua-parser-js';
const parser = new UAParser(ua);
const result = parser.getResult();
// 输出:{ browser: {...}, os: {...}, device: {...} }
在做功能降级时,我们经常需要判断“浏览器是否大于某版本”。
bowser 提供了内置的 satisfies 方法,语义最清晰。
import bowser from 'bowser';
const isValid = bowser.getParser(ua).satisfies({
chrome: ">=80",
firefox: ">=75"
});
// 返回 true 或 false
platform 没有内置版本比较逻辑,需要手动解析版本号字符串。
import platform from 'platform';
const info = platform.parse(ua);
const version = parseFloat(info.version);
const isValid = info.name === 'Chrome' && version >= 80;
// 需要自行处理版本字符串比较逻辑
ua-parser-js 同样需要手动比较,但它提供的版本信息结构更标准化。
import UAParser from 'ua-parser-js';
const parser = new UAParser(ua);
const browser = parser.getBrowser();
const isValid = browser.name === 'Chrome' && parseFloat(browser.version) >= 80;
// 需自行编写比较逻辑
当需要区分 iOS 与 Android,或识别特定设备型号时,库的能力差异明显。
bowser 主要关注浏览器本身,操作系统信息较为基础。
import bowser from 'bowser';
const os = bowser.getParser(ua).getOS();
// 输出:{ name: 'iOS', version: '14.5' }
// 不提供具体设备型号(如 iPhone 12)
platform 提供基本的操作系统名称,但设备识别能力有限。
import platform from 'platform';
const info = platform.parse(ua);
console.log(info.os);
// 输出:'iOS 14.5'
// 难以获取具体的设备硬件信息
ua-parser-js 提供独立的 device 对象,能识别厂商和型号。
import UAParser from 'ua-parser-js';
const parser = new UAParser(ua);
const device = parser.getDevice();
// 输出:{ vendor: 'Apple', model: 'iPhone', type: 'mobile' }
在生产环境中,解析库的安全性至关重要,尤其是防止正则表达式拒绝服务攻击(ReDoS)。
bowser 代码库较小,正则逻辑相对简单,历史安全记录良好。
// bowser 内部维护正则表
// 社区响应速度快,Issue 修复及时
platform 曾曝出 CVE-2021-23358 安全漏洞,且近年来更新频率极低。
// 已知存在 ReDoS 风险
// 建议避免在新项目中使用,迁移成本较低
ua-parser-js 也曾受 CVE-2021-23358 影响,但已发布补丁并持续维护。
// 已修复已知漏洞
// 拥有活跃的维护团队和定期的安全更新
| 特性 | bowser | platform | ua-parser-js |
|---|---|---|---|
| 包体积 | ⚡ 极小 (~5kb) | 🍃 小 (~10kb) | 📦 中等 (~20kb) |
| 浏览器判断 | ✅ 内置版本比较 | ❌ 需手动比较 | ❌ 需手动比较 |
| 设备型号识别 | ❌ 不支持 | ❌ 不支持 | ✅ 支持厂商/型号 |
| 维护状态 | 🟢 活跃 | 🔴 停滞/低风险 | 🟢 活跃 |
| 安全性 | 🟢 高 | 🟠 已知漏洞 | 🟢 高(已修复) |
bowser 是轻量级首选 🪶。如果你的需求仅限于“判断浏览器版本”来决定是否加载 polyfill 或展示提示,它的 API 最友好,体积最小。
ua-parser-js 是全能型选手 🛡️。如果你需要构建用户画像、分析设备分布或进行精细化的兼容性控制,它提供的数据维度最丰富。
platform 应逐步淘汰 🗑️。鉴于其维护状态和安全历史,除非受限于遗留系统依赖,否则不应在新架构中引入。
最终建议:现代前端项目推荐优先使用 bowser 处理逻辑判断,配合 ua-parser-js 处理数据分析需求。避免使用 platform 以降低潜在的安全维护成本。
选择 bowser 如果你的主要需求是判断浏览器类型和版本(例如检查是否为 Chrome 80+),且希望包体积尽可能小。它的 API 设计直观,适合在现代前端项目中做简单的兼容性降级或功能开关。
不建议在新项目中选择 platform。该库近年来维护活动较少,且历史上曾出现过安全漏洞(如 ReDoS 攻击风险)。除非你正在维护依赖它的旧系统,否则应优先考虑更活跃的替代方案。
选择 ua-parser-js 如果你需要获取详细的设备信息(如手机型号)、操作系统版本或渲染引擎详情。它是社区标准之一,更新频繁,适合需要高准确度解析复杂 User-Agent 字符串的企业级应用。
A small, fast and rich-API browser/platform/engine detector for both browser and node.
Don't hesitate to support the project on Github or OpenCollective if you like it ❤️ Also, contributors are always welcome!
The library is made to help to detect what browser your user has and gives you a convenient API to filter the users somehow depending on their browsers. Check it out on this page: https://bowser-js.github.io/bowser-online/.
Version 2.0 has drastically changed the API. All available methods are on the docs page.
For legacy code, check out the 1.x branch and install it through npm install bowser@1.9.4.
First of all, require the library. This is a UMD Module, so it will work for AMD, TypeScript, ES6, and CommonJS module systems.
const Bowser = require("bowser"); // CommonJS
import * as Bowser from "bowser"; // TypeScript
import Bowser from "bowser"; // ES6 (and TypeScript with --esModuleInterop enabled)
By default, the exported version is the ES5 transpiled version, which do not include any polyfills.
In case you don't use your own babel-polyfill you may need to have pre-built bundle with all needed polyfills.
So, for you it's suitable to require bowser like this: require('bowser/bundled').
As the result, you get a ES5 version of bowser with babel-polyfill bundled together.
You may need to use the source files, so they will be available in the package as well.
Often we need to pick users' browser properties such as the name, the version, the rendering engine and so on. Here is an example how to do it with Bowser:
const browser = Bowser.getParser(window.navigator.userAgent);
console.log(`The current browser name is "${browser.getBrowserName()}"`);
// The current browser name is "Internet Explorer"
Modern browsers support User-Agent Client Hints, which provide a more privacy-friendly and structured way to access browser information. Bowser can use Client Hints data to improve browser detection accuracy.
// Pass Client Hints as the second parameter
const browser = Bowser.getParser(
window.navigator.userAgent,
window.navigator.userAgentData
);
console.log(`The current browser name is "${browser.getBrowserName()}"`);
// More accurate detection using Client Hints
Bowser provides methods to access and query Client Hints data:
const browser = Bowser.getParser(
window.navigator.userAgent,
window.navigator.userAgentData
);
// Get the full Client Hints object
const hints = browser.getHints();
// Returns the ClientHints object or null if not provided
// Check if a specific brand exists
if (browser.hasBrand('Google Chrome')) {
console.log('This is Chrome!');
}
// Get the version of a specific brand
const chromeVersion = browser.getBrandVersion('Google Chrome');
console.log(`Chrome version: ${chromeVersion}`);
The Client Hints object structure:
{
brands: [
{ brand: 'Google Chrome', version: '131' },
{ brand: 'Chromium', version: '131' },
{ brand: 'Not_A Brand', version: '24' }
],
mobile: false,
platform: 'Windows',
platformVersion: '15.0.0',
architecture: 'x86',
model: '',
wow64: false
}
Note: Client Hints improve detection for browsers like DuckDuckGo and other Chromium-based browsers that may have similar User-Agent strings. When Client Hints are not provided, Bowser falls back to standard User-Agent string parsing.
or
const browser = Bowser.getParser(window.navigator.userAgent);
console.log(browser.getBrowser());
// outputs
{
name: "Internet Explorer"
version: "11.0"
}
or
console.log(Bowser.parse(window.navigator.userAgent));
// outputs
{
browser: {
name: "Internet Explorer"
version: "11.0"
},
os: {
name: "Windows"
version: "NT 6.3"
versionName: "8.1"
},
platform: {
type: "desktop"
},
engine: {
name: "Trident"
version: "7.0"
}
}
You can also use Bowser.parse() with Client Hints:
console.log(Bowser.parse(window.navigator.userAgent, window.navigator.userAgentData));
// Same output structure, but with enhanced detection from Client Hints
You could want to filter some particular browsers to provide any special support for them or make any workarounds. It could look like this:
const browser = Bowser.getParser(window.navigator.userAgent);
const isValidBrowser = browser.satisfies({
// declare browsers per OS
windows: {
"internet explorer": ">10",
},
macos: {
safari: ">10.1"
},
// per platform (mobile, desktop or tablet)
mobile: {
safari: '>=9',
'android browser': '>3.10'
},
// or in general
chrome: "~20.1.1432",
firefox: ">31",
opera: ">=22",
// also supports equality operator
chrome: "=20.1.1432", // will match particular build only
// and loose-equality operator
chrome: "~20", // will match any 20.* sub-version
chrome: "~20.1" // will match any 20.1.* sub-version (20.1.19 as well as 20.1.12.42-alpha.1)
});
Settings for any particular OS or platform has more priority and redefines settings of standalone browsers. Thus, you can define OS or platform specific rules and they will have more priority in the end.
More of API and possibilities you will find in the docs folder.
.satisfies()By default you are supposed to use the full browser name for .satisfies.
But, there's a short way to define a browser using short aliases. The full
list of aliases can be found in the file.
This project exists thanks to all the people who contribute. [Contribute].
Become a financial contributor and help us sustain our community. [Contribute]
Support this project with your organization. Your logo will show up here with a link to your website. [Contribute]
Licensed as MIT. All rights not explicitly granted in the MIT license are reserved. See the included LICENSE file for more details.