在 Linux 上的 azure 函数节点上部署时,Puppeteer 抛出启动异常

Puppeteer throws launch exception when deployed on azure functions node on Linux

问题:使用 puppeteer 获取网站的屏幕截图。在开发机器上工作正常,但在部署到云上的 Azure Functions 时抛出以下异常。

环境:在 Azure 上(节点 12,Linux,消费计划),函数使用服务总线主题触发。

错误:

Result: Failure Exception: Error: Failed to launch the browser process! spawn 
/home/site/wwwroot/node_modules/puppeteer/.local-chromium/linux-818858/chrome-linux/chrome 
EACCES TROUBLESHOOTING: https://github.com/puppeteer/puppeteer/blob/main/docs/troubleshooting.md 
Stack: Error: Failed to launch the browser process! 
spawn /home/site/wwwroot/node_modules/puppeteer/.local-chromium/linux-818858/chrome-linux/chrome 
EACCES TROUBLESHOOTING: https://github.com/puppeteer/puppeteer/blob/main/docs/troubleshooting.md 
at onClose (/home/site/wwwroot/node_modules/puppeteer/lib/cjs/puppeteer/node/BrowserRunner.js:193:20) 
at ChildProcess.<anonymous> (/home/site/wwwroot/node_modules/puppeteer/lib/cjs/puppeteer/node/BrowserRunner.js:185:85)
at ChildProcess.emit (events.js:314:20) at Process.ChildProcess._handle.onexit (internal/child_process.js:274:12)
at onErrorNT (internal/child_process.js:470:16) at processTicksAndRejections (internal/process/task_queues.js:84:21)

我遵循了 puppeteer 故障排除文档中的建议,但仍然遇到同样的问题。

我尝试过的午餐设置

let browser = await puppeteer.launch({ ignoreDefaultArgs: ['--disable-extensions'] });

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

let browser = await puppeteer.launch({ headless: true });   

let browser = await puppeteer.launch({ args: ['--no-sandbox', '--disable-setuid-sandbox'] });
以上的

None 有效。他们都抛出相同的错误。

我在函数中检查了 FTPing,chrome 文件 puppeteer 正在寻找,存在。

提前致谢。

Azure 在 Linux 消费计划中具有 运行 headless Chromium 的必要依赖项。所以我们可以使用Azure函数中的包puppeteer。但是我们需要使用远程构建来部署应用程序。详情请参考Azure feedback and the blog.

例如

  1. 创建 Azure 函数应用

  2. 创建 Azure 函数项目

一个。安装包

  npm install puppeteer

b。 function.json

{
  "bindings": [
    {
      "name": "mySbMsg",
      "type": "serviceBusTrigger",
      "direction": "in",
      "topicName": "bowman1012",
      "subscriptionName": "test",
      "connection": "bowman1012_SERVICEBUS"
    },
    {
      "type": "blob",
      "direction": "out",
      "name": "outputBlob",
      "path": "outcontainer/{rand-guid}.png",
      "connection": "AzureWebJobsStorage"
    }
  ]
}

c。代码

const puppeteer = require("puppeteer");

module.exports = async function (context, mySbMsg) {
  context.log(
    "JavaScript ServiceBus topic trigger function processed message",
    mySbMsg
  );
  const browser = await puppeteer.launch({ headless: true });
  const page = await browser.newPage();
  await page.goto("https://google.com/");
  const screenshotBuffer = await page.screenshot({ fullPage: true });
  await browser.close();
  context.bindings.outputBlob = screenshotBuffer;
};

  1. 在根项目文件夹中添加.funcignore文件
*.js.map
*.ts
.git*
.vscode
local.settings.json
test
tsconfig.json
node_modules
  1. 部署到 Azure
func azure functionapp publish $appName --build remote
  1. 测试

更新

由于您使用 typescript 创建 Azure 函数,我们需要更新 .funcignore 如下

*.js.map
.git*
.vscode
local.settings.json
test
node_modules

例如

我的函数代码index.ts

import { AzureFunction, Context } from "@azure/functions";
import { ServiceBusMessage } from "@azure/service-bus";
import puppeteer from "puppeteer";
import { BlobServiceClient } from "@azure/storage-blob";

const serviceBusTopicTrigger: AzureFunction = async function (
  context: Context,
  mySbMsg: ServiceBusMessage
): Promise<void> {
  try {
    const promotionId = context.bindingData.userProperties.promotionId;
    context.log(
      "Player Screen Grabber ServiceBus topic trigger function processing message started",
      promotionId
    );
    const playerURL = "https://www.google.com/";
    let browser = await puppeteer.launch({ headless: true });
    let page = await browser.newPage();
    await page.goto(playerURL, { waitUntil: "networkidle2" });
    await page.setViewport({ width: 1920, height: 1080 });
    const screenshotBuffer = await page.screenshot({
      encoding: "binary",
    });
    await page.close();
    await browser.close();
    // the storage account connection string
    const constr = process.env["AzureWebJobsStorage"] + "";
    const blobserviceClient = BlobServiceClient.fromConnectionString(constr);
    const containerClient = blobserviceClient.getContainerClient(
      "outcontainer"
    );
    const blob = containerClient.getBlockBlobClient(`${promotionId}.png`);
    await blob.uploadData(screenshotBuffer);
    context.log(
      "Player Screen Grabber ServiceBus topic trigger function processing message ended",
      promotionId
    );
  } catch (error) {
    throw error;
  }
};

export default serviceBusTopicTrigger;

部署到 Azure

func azure functionapp publish $appName --build remote

测试

我的服务总线消息

结果