代码之家  ›  专栏  ›  技术社区  ›  ChethiyaKD

为什么Puppeter PDF生成在Windows上不起作用?

  •  0
  • ChethiyaKD  · 技术社区  · 1 年前

    我有一个NodeJs应用程序,试图从HTML生成PDF。它适用于Mac,但不适用于Windows(超时)。这是代码。

    const puppeteer = require('puppeteer');
    const fs = require('fs');
    
    const init = async () => {
        try {
            const browser = await puppeteer.launch({headless: true});
            const page = await browser.newPage();
    
            await page.setContent('<h1>Hello World</h1>');
            await page.emulateMediaType('screen');
            await page.pdf({
                path: 'hello-world.pdf',
                format: 'A4',
                printBackground: true,
                timeout: 0
            });
    
            console.log('PDF Generated');
            await browser.close();
            process.exit()
    
        } catch (error) {
            console.log(error)
        }
    };
    
    init()
    

    调用page.pdf方法后,它会等待很长时间并超时。 ProtocolError: Page.printToPDF timed out. Increase the 'protocolTimeout' setting in launch/connect calls for a higher timeout if needed.

    但在我的M1 MacBook Pro上,它就像一个魅力。

    在Windows 11虚拟机(Parallels)和几台Windows 11笔记本电脑上尝试了这一点。但运气不佳。

    我在这里做错了什么?我还需要添加其他内容吗?

    谢谢!

    节点:v2015.0

    木偶:^22.12.1

    1 回复  |  直到 1 年前
        1
  •  3
  •   Fiddlesteaks    1 年前

    根据你自己回答的io日志,我不确定你是否真的能看到 [URL] 它会打印到控制台,但会导致 this documentation of the Chromium Sandbox 它指定您可能必须根据安装方式自行设置所需的权限。在Windows上使用Puppeteer时可能会出现这种情况。这也基本上被复制粘贴到 Puppeteer Troubleshooting ,它还提供了一种如何设置所需权限的方法 icacls .

    在我看来,这是一种比完全禁用沙盒更安全的方法。但是,提供的命令中使用的SID S-1-15-2-1 结果到 ALL APPLICATION PACKAGES ,这是相当广泛的。这就是为什么两份文档都提到“在高安全性环境中,应该使用更严格的SID,比如安装程序中的SID”(我很确定提供的安装程序链接实际上引用了错误的LOC,它实际上应该导致 here ). 然而,Chromium Sandbox文档提到 ALL RESTRICTED APPLICATION PACKAGES SID(Windows 10 RS2或更高版本),未显示在 Microsoft's official list of "Well-Known SIDs" 但是 S-1-15-2-2 .

    解决方案 :这就是为什么我认为,与其禁用沙盒,不如在CMD中执行以下命令来授予所需的权限,这样会更安全:

    icacls %USERPROFILE%/.cache/puppeteer/chrome /grant *S-1-15-2-2:(OI)(CI)(RX)
    

    不需要以管理员身份运行cmd(至少我不需要)。路径是Puppeter通常存储其chrome箱的地方,但如果您在Puppeter中指定了不同的路径,则可能需要对其进行调整。

    问题是, S-1-15-2-2 仍然是一个相当宽泛的SID,但我无法找到一个更窄的SID。如果你检查 the installer ,你可以看到它设置 GENERIC_READ (GR) FILE_DELETE_CHILD (DC) 对于SID AUTHENTICATED_USERS 然而,这不可能是全部,因为 LOC in "sandbox_win.cc" that throws your error 实际检查 GENERIC_READ (GR) GENERIC_EXECUTE (GE) (所以 (RX) 总计)。我非常确定用户SID和组SID不起作用。我认为起作用的是以以下开头的“登录”SID S-1-5-5- ,但每次都会改变。我将进一步探讨中的信息 this answer 如果我找到更安全的解决方案,请编辑此内容。此外,我甚至不确定为什么包SID有效,因为它们应该只适用于Windows应用商店应用程序、在应用容器中运行的进程或UWP。所以它绝对不是Windows应用商店应用程序,我也用Process Explorer检查过,有问题的进程没有在应用容器中运行。我无法确定Windows上的Chromium是否是UWP。

        2
  •  2
  •   ChethiyaKD    1 年前

    几个小时后,我找到了问题所在。

    启动浏览器并记录浏览器日志后 await puppeteer.launch({headless: true, dumpio:true}); 它记录了这一点:

    [16848:6956:0703/000025.226:ERROR:sandbox_win.cc(913)] Sandbox cannot access executable. Check filesystem permissions are valid. See [URL]: Access is denied. (0x5)
    
    DevTools listening on ws://[URL][16848:7356:0703/000025.488:ERROR:network_service_instance_impl.cc(600)] Network service crashed, restarting service.
    [16848:6956:0703/000026.330:ERROR:sandbox_win.cc(913)] Sandbox cannot access executable. Check filesystem permissions are valid. See [URL]: Access is denied. (0x5)
    

    所以我能够找到添加 args: ['--no-sandbox', '--disable-setuid-sandbox'] 这是一种解决方法,但不建议使用 https://stackoverflow.com/a/53975412/9814969

    const browser = await puppeteer.launch({ headless: true, args: ['--no-sandbox', '--disable-setuid-sandbox'] }); 工作!

    这似乎是基于Linux的系统上的一个常见问题,但我在Windows上尝试过。因此,添加此作为答案

        3
  •  1
  •   Ako    1 年前

    多亏了@Fiddlestekes的响应,我不得不运行这两个命令:

    icacls $env:USERPROFILE/.cache/puppeteer/chrome-headless-shell /grant *S-1-15-2-2":(OI)(CI)(RX)"

    icacls $env:USERPROFILE/.cache/puppeteer/chrome /grant *S-1-15-2-2":(OI)(CI)(RX)"

    那么pdf生成无需 args: ['--no-sandbox', '--disable-setuid-sandbox']