使用 @puppeteer/browsers 的 canDownload() 提前探测浏览器包是否可下载
canDownload() 是 Puppeteer 官方浏览器管理库 @puppeteer/browsers 提供的公开 API,用于在真正执行安装之前判断某个浏览器(Chrome / ChromeDriver / Chrome for Testing / Firefox 等)的指定平台与 buildId 组合是否存在可下载的二进制归档。本文围绕其函数签名、参数语义与底层探测机制展开,结合仓库源码与测试用例,帮助你把它正确接入预检、断点续传、多镜像回退等下载流程。
canDownload() 的定位与使用场景
该函数属于 @puppeteer/browsers 的程序化(programmatic)API 家族。同族 API 还包括 install()、getInstalledBrowsers()、uninstall()、getDownloadUrl(),它们统一从 packages/browsers/src/main.ts 导出。canDownload 本身是其中最轻量的一员:它不会下载任何字节,只负责回答"这个目标可不可下载"这一个布尔问题。
典型应用场景包括:
- 在执行耗时的大体积浏览器下载前做可用性预检,避免失败后再报错;
- 根据检测结果动态切换官方源与自定义镜像源;
- 在 CI 中区分"目标版本暂未发布"与"网络故障"两类失败。
函数完整签名定义在 docs/browsers-api/browsers.candownload.md:
export declare function canDownload(options: InstallOptions): Promise<boolean>;
它接受一个 InstallOptions 参数,返回 Promise<boolean>:当目标归档存在且可访问时解析为 true,否则为 false。
传入参数:InstallOptions 逐项说明
canDownload 与 install 共用同一个 InstallOptions 配置对象(其 TypeScript 定义位于 packages/browsers/src/install.ts)。其中真正影响探测结果的字段如下。
| 字段 | 类型 | 必填 | 说明与默认值 |
|---|---|---|---|
browser |
Browser 枚举 |
是 | 目标浏览器。参考 Browser 枚举 |
buildId |
string |
是 | 目标版本标识,应能唯一对应一份二进制,并作为缓存目录的组成部分 |
platform |
BrowserPlatform 枚举 |
否 | 目标操作系统与架构组合,如 LINUX、MAC_ARM、WIN64。默认自动探测当前平台(调用 detectBrowserPlatform());若自动探测失败且未显式指定,函数会抛出异常 |
baseUrl |
string |
否 | 下载源主机。默认是 https://storage.googleapis.com/chrome-for-testing-public(Chrome 系列)或 https://archive.mozilla.org/pub/firefox/nightly/latest-mozilla-central(Firefox) |
providers |
BrowserProvider[] |
否 | 自定义下载源提供者。多个可链式传入,按顺序尝试,官方默认源自动作为最后兜底 |
cacheDir |
string |
否(探测时并不真正落盘) | 浏览器安装根目录。canDownload 不创建目录,但保持与 install 一致的调用形态 |
logger |
Logger |
否 | 调试日志输出(puppeteer:browsers:* 通道) |
需要注意:installDeps、expectedHash、unpack、downloadProgressCallback、buildIdAlias 等字段更多服务于真正的安装流程,在 canDownload 中并不参与探测决策。
一个最小化的探测调用示例:
import {Browser, BrowserPlatform, canDownload} from '@puppeteer/browsers';
const available = await canDownload({
browser: Browser.CHROME,
buildId: '131.0.6778.85',
platform: BrowserPlatform.LINUX,
cacheDir: '/tmp/puppeteer-browsers',
});
console.log(available); // true | false
BrowserPlatform 的合法取值(枚举定义见 BrowserPlatform 枚举)按"OS 平台 × 架构"划分,例如 LINUX、MAC、MAC_ARM、WIN32、WIN64,这决定了归档文件(如 chrome-linux64.zip)的选取。
底层探测原理:源码调用链
canDownload 的实现位于 packages/browsers/src/install.ts,整体逻辑可以概括为"拼接候选下载 URL → 逐个发送 HTTP HEAD 请求验证":
export async function canDownload(options: InstallOptions): Promise<boolean> {
options.platform ??= detectBrowserPlatform();
if (!options.platform) {
throw new Error(
`Cannot download a binary for the provided platform: ${os.platform()} (${os.arch()})`,
);
}
// Always use plugin architecture (uses default provider if none specified)
const providers = [
...(options.providers || []),
new DefaultProvider(options.baseUrl),
];
const downloadOptions = {
browser: options.browser,
platform: options.platform,
buildId: options.buildId,
};
// Check if any provider can provide a valid, downloadable URL
for (const provider of providers) {
if (!(await provider.supports(downloadOptions))) {
continue;
}
const url = await provider.getDownloadUrl(downloadOptions);
if (url && (await headHttpRequest(url))) {
return true;
}
}
return false;
}
据此可以还原出它的关键行为,每一条都与具体代码一一对应:
- 平台自动补全:未显式提供
platform时调用detectBrowserPlatform();探测不到会直接抛错(错误信息形如Cannot download a binary for the provided platform: linux (x64)),而不是静默返回false。 - Provider 插件化探测:即使不传
providers,也会构造一个DefaultProvider。DefaultProvider的supports()恒返回true,其getDownloadUrl()通过各浏览器的downloadUrls映射拼出归档地址,见 packages/browsers/src/DefaultProvider.ts。若传入了多个自定义 provider,则按数组顺序逐个尝试,任一 provider 命中即返回true。 - HEAD 请求验证存在性:核心校验由
headHttpRequest(url)完成,见 packages/browsers/src/httpUtil.ts。它向 URL 发起 HTTPHEAD请求,仅当响应状态码为 200 时才算可下载;同时会跟随 3xx 重定向,并在请求出错或抛异常时吞掉错误、返回false——因此网络临时故障会被折算成"不可下载"。 - 短路返回:一旦某个 provider 的 URL 通过 HEAD 校验立即返回
true;所有 provider 都失败才返回false。这意味着canDownload天然支持"公司内部镜像优先、官方源兜底"的多源回退语义。
与 install()、getDownloadUrl() 的分工协作
理解了调用链后,canDownload 在 API 家族中的位置就非常清晰:
install()会真正下载、解压并安装浏览器归档(解压逻辑见 installWithProviders 对 provider 的遍历与回退);getDownloadUrl(browser, platform, buildId, baseUrl)只负责计算下载 URL,不发起任何网络请求,见 packages/browsers/src/install.ts;canDownload()在两者之间:在getDownloadUrl()得到 URL 之后、install()真正下载之前,用一次轻量 HEAD 请求确认该 URL 是否真实可达。
因此,一个稳妥的接入模式是先探测、后安装:
import {
Browser,
BrowserPlatform,
canDownload,
install,
} from '@puppeteer/browsers';
const target = {
browser: Browser.CHROME,
buildId: '131.0.6778.85',
platform: BrowserPlatform.LINUX,
cacheDir: './.browser-cache',
};
if (await canDownload(target)) {
await install(target); // 确认可用后再执行真实安装
} else {
console.warn('目标版本暂不可用,跳过安装');
}
测试用例如何验证探测行为
仓库为 canDownload 提供了覆盖"可下载 / 不可下载"两个方向的真实网络测试,可作为理解其语义的最佳佐证:
- 在 packages/browsers/test/src/chrome/install.test.ts 中,用真实的
testChromeBuildId配合本地测试服务器地址调用canDownload,断言结果为true;再用一个不存在的buildId: 'unknown'断言结果为false。 - 同类用例还出现在 chromedriver/install.test.ts 与 chrome-headless-shell/install.test.ts,验证
canDownload对CHROMEDRIVER、CHROME_HEADLESS_SHELL等浏览器类型同样生效。
这些测试同时揭示了一个容易被忽略的细节:测试通过 baseUrl: getServerUrl() 指向本地测试服务器,说明 baseUrl 参数在探测中起决定性作用——它可以替换默认的官方下载源,这为自建内网镜像后复用 canDownload 做预检提供了依据。
注意事项与限制
综合源码与接口文档,使用时有以下几点需要留意:
- 平台探测失败会抛异常:在无法识别平台的环境(如非标准 OS/架构组合)中,
canDownload不会返回false,而是抛出Cannot download a binary for the provided platform: ...。调用方应做好异常捕获。 - 只验证"URL 可达",不验证"包体完整":HEAD 200 只代表资源存在;归档的 SHA-256 完整性校验依赖
install()的expectedHash参数,是两件不同的事。 - 代理环境依赖可选依赖:库与 CLI 都遵循
HTTP_PROXY、HTTPS_PROXY、NO_PROXY环境变量,但需要额外安装proxy-agent包才会走代理(见 docs/browsers-api/index.md),否则回落到 Node.js 默认 agent 直连。 - 自定义 provider 不受官方保障:
providers允许接入企业镜像等替代源,但文档明确提示 Custom providers 不在 Puppeteer 官方支持范围之内,二进制兼容性、功能集成与测试责任均由使用方自行承担。
综上,canDownload 是 @puppeteer/browsers 中结构最简单、却非常适合放在"下载前"做预检的公共 API。把它的探测语义、返回时机(true / false / 抛错)与多 provider 链式回退机制纳入下载编排逻辑,可以有效提升浏览器自动管理的健壮性与可观测性。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0629
MiniCPM5-2BMiniCPM5-2B 是一款面向端侧、本地部署和资源受限场景的 2B 稠密 Transformer,能够达到同尺寸开源模型 SOTA 水平。Markdown00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00