Browsershot 改变浏览器语言:setEnvironmentOptions 的用法与底层原理

原创2026-10-12 12:29:501,923 阅读
文章标签:后端图像处理

Browsershot 改变浏览器语言:setEnvironmentOptions 的用法与底层原理

导读

本文围绕 changing-the-language-of-the-browser.md 展开,讲解如何通过 Browsershot 的 setEnvironmentOptions() 方法为无头 Chromium 注入 LANG 等环境变量,从而让页面按指定语言(locale)渲染。你将掌握该方法的完整调用方式、它在 src/Browsershot.php 与 bin/browser.cjs 中的传递链路,以及与 Accept-Language 请求头、setNodeEnv 等相近方案的区别,以便在实际项目中按需选用。

为什么需要改变浏览器的语言

无头浏览器抓取页面时,站点往往依据浏览器进程的语言/区域设置来决定返回内容的语言。例如访问 https://example.com,默认环境下可能返回英文界面,而业务上需要以 en-GB(英式英语)或 de-DE(德语)等特定语言加载页面。Browsershot 官方文档给出的方案,就是通过 setEnvironmentOptions 向浏览器进程注入 LANG 环境变量,让 Chromium 以指定语言环境启动。

该能力属于 Miscellaneous Options 系列,与同目录下 passing-environment-variables-to-the-browser.md 是同一套 API:前者侧重改变浏览器语言,后者用于注入任意自定义环境变量(如 TZ 时区),二者底层实现完全一致。

基本用法:setEnvironmentOptions 注入 LANG

在文件顶部引入命名空间后(参见 docs/usage/introduction.md),即可链式调用:

use Spatie\Browsershot\Browsershot;

Browsershot::url('https://example.com')
    ->setEnvironmentOptions([
        'LANG' => 'en-GB',
    ])
    ->save('example.pdf'); // 也可以换成 ->save('example.png') 等

要点说明:

  • setEnvironmentOptions() 接收一个键值对数组,键为环境变量名,值为其取值;
  • 该方法返回 self,可继续链式调用其它方法(截图、PDF、HTML 等),示例中的 ... 即代表后续任意操作;
  • LANG 是 POSIX 系统的标准语言环境变量,取值建议使用完整的 locale 标识(如 en-GB、de-DE.UTF-8),让 Chromium 与系统本地化机制都能正确识别。

底层原理:从 PHP 选项到 Chromium 进程

1. 选项写入命令 JSON

setEnvironmentOptions 的实现非常简洁,它把传入数组整体写入 env 这个选项键:

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

setOption()(src/Browsershot.php)会通过 arraySet() 把键值写入内部 additionalOptions 数组,支持点分隔的嵌套键名;随后在 createCommand()(src/Browsershot.php)中通过 array_merge_recursive 合并进最终命令,随 Node 脚本一起执行。

2. Node 端注入 puppeteer 启动参数

PHP 端会把命令 JSON 传给 bin/browser.cjs(该脚本本质上是 puppeteer 的封装)。在浏览器启动处可以看到:

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

即 env 选项被直接传给 puppeteer 的 launch(),成为 Chromium 子进程的环境变量集合。这印证了文档中的说法:LANG 会作用于整个浏览器进程,而不仅仅是单次页面请求。

3. 同名变量覆盖顺序

从上面 spread 的书写顺序可以推断:options.env(即你通过 setEnvironmentOptions 传入的变量)在前,process.env(Node 进程自身环境)在后,因此 若自定义变量与 Node 运行环境中已存在的变量同名,后者会覆盖前者。例如当服务器本身已设置了 LANG 时,注入同名的 LANG 未必生效——这是从 bin/browser.cjs 源码结构可推断出的行为,在依赖系统默认语言环境的场景下需特别留意。

4. 测试用例佐证

仓库测试 tests/BrowsershotTest.php 明确验证了该方法的输出结构:

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' => [
            // ...
            'env' => [
                'TZ' => 'Pacific/Auckland',
            ],
        ],
    ], $instance->createScreenshotCommand('screenshot.png'));
});

可见 env 会以顶层选项的形式出现在最终命令中,与 setEnvironmentOptions(['LANG' => 'en-GB']) 的用法完全对应。

同时注入多个环境变量

setEnvironmentOptions 接受任意数量的键值对,例如同时指定语言与时区:

Browsershot::url('https://example.com')
    ->setEnvironmentOptions([
        'LANG' => 'de-DE',
        'TZ'   => 'Europe/Berlin',
    ])
    ->save('example.pdf');

也可以多次调用,最终通过 array_merge_recursive 合并生效。

与相近方案的区分

setNodeEnv:作用于 Node 进程,而非浏览器

注意区分 src/Browsershot.php 中的 setNodeEnv():它设置的是 Node 进程本身 的环境变量,由 buildEnvVarsCommand()(src/Browsershot.php)拼进命令行前缀;而 setEnvironmentOptions() 注入的是 Chromium 浏览器进程 的环境变量。前者影响 puppeteer/Node 侧,后者影响页面渲染侧,按需选择。

Accept-Language 请求头:控制 HTTP 层语言协商

如果目标站点是根据 HTTP 请求头协商语言,而非依赖浏览器进程环境,更直接的做法是设置 Accept-Language 头,参见 adding-extra-headers-to-the-navigational-request.md:

Browsershot::url('https://example.com')
    ->setExtraNavigationHttpHeaders(['Accept-Language' => 'en-GB'])
    ->save('example.pdf');

两者侧重点不同:LANG 环境变量影响浏览器进程的语言环境(如默认字体、日期/数字本地化规则),Accept-Language 影响页面发起的导航请求的语言协商。实际排障时可以两个维度结合排查。

注意事项与适用前提

  • 平台差异:在 Windows 上,getWindowsEnv() 只透传 LOCALAPPDATA、Path、SystemRoot、USERPROFILE 等系统关键变量,注入的 LANG 等 POSIX 风格变量在 Windows 环境下意义有限;该方案主要面向 Linux/macOS 类 POSIX 环境。
  • 覆盖问题:如前所述,process.env 中的同名变量会覆盖自定义值,使用前可用 setNodeEnv 或直接核对运行环境,避免静默失效。
  • 站点语言机制差异:部分站点通过 cookie、地理位置或登录态决定语言,仅设置 LANG 不一定能改变页面内容,此时应结合 using-cookies.md 等方案综合处理。
  • 调试建议:若设置了 LANG 后页面语言未变化,可先确认浏览器进程实际继承的环境变量(如临时打印 process.env),再决定改用 Accept-Language 头或 Chromium 的 --lang 启动参数。

小结

setEnvironmentOptions(['LANG' => 'en-GB']) 是 Browsershot 官方推荐的改变浏览器语言方式,其本质是把 env 选项透传给 puppeteer 的 launch(),最终成为 Chromium 子进程的环境变量。理解 src/Browsershot.php 到 bin/browser.cjs 的传递链路,以及它与 setNodeEnv、Accept-Language 头的边界,即可在不同语言协商场景下准确选型,并通过 tests/BrowsershotTest.php 的用例结构验证最终命令是否正确。

登录后查看全文
browsershot