Browsershot 向浏览器实例传递环境变量:setEnvironmentOptions 用法与底层原理

原创2026-10-12 13:01:052,000 阅读
文章标签:后端图像处理

Browsershot 向浏览器实例传递环境变量:setEnvironmentOptions 用法与底层原理

本文围绕 Spatie Browsershot 的 setEnvironmentOptions() 方法展开,讲解如何在调用 Chromium(Chrome)渲染网页、截图或生成 PDF 时,把自定义环境变量(如时区 TZ)注入浏览器进程。读完你将掌握该 API 的标准写法、它与 setNodeEnv() 的本质区别,以及从 PHP 到 Puppeteer 的完整变量传递链路,可用于解决时区错乱、区域设置、证书代理等真实渲染场景。

一、为什么需要向浏览器传递环境变量

Chromium 是独立于 PHP 进程的浏览器实例,它读取的是自身进程的环境变量。当页面脚本依赖某些环境变量来决定渲染结果时(例如 JavaScript 中的 Intl.DateTimeFormat 需要正确的 TZ 时区,或页面需要读取特定代理、语言环境配置),PHP 侧设置 putenv() 并不会影响浏览器。

Browsershot 为此提供了两个层面的环境变量注入入口:

  • setEnvironmentOptions(array $options):注入到 Chromium 浏览器进程,影响页面渲染本身;
  • setNodeEnv(array $envVars):注入到 Node(Puppeteer)进程,影响桥接脚本运行环境(见 src/Browsershot.php)。

两者互不替代,本文重点讲解前者。

二、核心用法:setEnvironmentOptions 标准示例

官方文档给出的最小示例即是最常见场景——为浏览器设置时区:

use Spatie\Browsershot\Browsershot;

Browsershot::url('https://example.com')
   ->setEnvironmentOptions(['TZ' => 'Pacific/Auckland'])
   ->save('example.png');

方法接受一个「键值对数组」,键为环境变量名,值为字符串,调用后返回 self,因此可以继续链式追加其他配置:

Browsershot::url('https://example.com')
   ->setEnvironmentOptions([
       'TZ'        => 'Asia/Shanghai',
       'LANG'      => 'zh_CN.UTF-8',
       'HTTP_PROXY' => 'http://127.0.0.1:7890',
   ])
   ->windowSize(1920, 1080)
   ->save('example.pdf');

实现上,该方法等价于调用 setOption('env', $options),把数组原样放入命令的 options.env 字段:

public function setEnvironmentOptions(array $options = []): self
{
    return $this->setOption('env', $options);
}

见 src/Browsershot.php。传空数组时等价于不设置该选项。

三、底层链路:环境变量如何从 PHP 到达 Chromium

整条链路分三段,每一段都有明确的源码依据:

1. PHP 侧组装命令:createCommand() 将 url、action、options 组装成数组,env 作为 options 的子键被 JSON 序列化后通过命令行传给 bin/browser.cjs(见 src/Browsershot.php 与 getFullCommand)。

2. 桥接脚本接收并合并:bin/browser.cjs 在调用 puppeteer.launch() 时,把自定义变量与 Node 进程自身环境合并后传给 Chromium:

browser = await puppet.launch({
    headless: options.newHeadless ? true : 'shell',
    executablePath: options.executablePath,
    args: options.args || [],
    pipe: options.pipe || false,
    env: {
        ...(options.env || {}),
        ...process.env
    },
    ...
});

见 bin/browser.cjs。这意味着传入的环境变量并非替换浏览器整个环境,而是与 Node 进程当前环境合并后一并生效——Chromium 仍能拿到 PATH、HOME 等系统变量。

3. Chromium 进程生效:Puppeteer 将合并后的 env 作为 Chromium 子进程的环境变量,页面内运行的 JavaScript(如 Intl、Date)随即感知到 TZ 等变量带来的行为差异。

四、setEnvironmentOptions 与 setNodeEnv 的区别

两者名称相近但作用对象完全不同,容易混淆:

方法 注入目标 底层机制 典型用途
setEnvironmentOptions() Chromium 浏览器进程 options.env → puppeteer.launch({ env }) 时区、语言、页面可见的环境变量
setNodeEnv() Node(Puppeteer 桥接)进程 nodeEnvVars → shell 前缀 KEY='value' NODE_ENV 等影响 Node 脚本自身的变量

setNodeEnv 的实现是把变量拼进命令行前缀(KEY='value' node browser.cjs ...),由 buildEnvVarsCommand() 生成,见 src/Browsershot.php。测试用例 tests/BrowsershotTest.php 通过 setNodeEnv(['NODE_ENV' => 'production']) 生成截图并断言输出文件存在,验证了该路径可用。

五、测试佐证:命令结构可验证

仓库测试 tests/BrowsershotTest.php 精确断言了 setEnvironmentOptions 最终产出的命令结构:

it('will allow passing environment variables', function () {
    $instance = Browsershot::url('https://example.com')
        ->setEnvironmentOptions([
            'TZ' => 'Pacific/Auckland',
        ]);

    $this->assertEquals([
        'url' => 'https://example.com',
        'action' => 'screenshot',
        'options' => [
            'path' => 'screenshot.png',
            'viewport' => ['width' => 800, 'height' => 600],
            'args' => [],
            'type' => 'png',
            'env' => ['TZ' => 'Pacific/Auckland'],
        ],
    ], $instance->createScreenshotCommand('screenshot.png'));
});

测试确认了三点事实:env 键位于 options 下;setEnvironmentOptions 不影响 args(Chromium 启动参数,由 --no-sandbox、--proxy-server 等另行生成);该 API 对截图、PDF、HTML 等所有 action 均通用。

六、使用注意事项

  • 生效时机:环境变量只在浏览器启动时注入,若在链式调用后手动 setOption('env', ...) 覆盖同名键,以最后一次赋值为准;
  • 合并规则:自定义变量与 Node 进程环境合并,因此不要用 setEnvironmentOptions 覆盖 PATH 等关键系统变量,以免破坏浏览器启动;
  • 敏感信息:环境变量会随命令 JSON 传递,避免放入密钥等敏感内容;若需减少命令行长度,可参考 写入选项文件 的 -f 方式;
  • 时区场景:TZ 是浏览器进程读取时区最直接的通道,使用 IANA 时区名(如 Pacific/Auckland、Asia/Shanghai)而非缩写,避免夏令时误判;
  • Windows 差异:在 Windows 上环境变量合并同样生效,但 Node 进程自身的 setNodeEnv 路径在 getFullCommand 中走数组参数交由 Symfony Process 处理,行为与类 Unix 略有差异。

七、延伸阅读

登录后查看全文
browsershot