javascript - Puppeteer 等待页面和 setTimeout 在 Firebase 云功能中不起作用

标签 javascript typescript firebase google-cloud-functions puppeteer

我正在尝试加载我在 firebase 上托管的页面,并使用 Puppeteer 将其转换为 pdf。
只需一个 html 页面即可正常工作。
现在我从 firebase 获取数据并将其显示在我的页面中,因此我需要等待页面完全加载才能创建 pdf。
当我使用 firebase 模拟器 npm run serve 在本地测试它时,它工作正常。
然而,它在云函数中不起作用,设置超时只是一直等待,直到函数超时。
日志显示 waitFor,一段时间后 函数执行耗时 120002 毫秒,完成状态:“超时”
我尝试了很多我不知道该怎么做的事情,我开始认为这是云函数中的错误。

import * as functions from 'firebase-functions';
// tslint:disable-next-line:no-duplicate-imports
import { VALID_MEMORY_OPTIONS } from 'firebase-functions';
// import * as puppeteer from 'puppeteer';

const runtimeOpts = {
  timeoutSeconds: 120,
  memory: VALID_MEMORY_OPTIONS[4],
};

// const cors = require('cors')({ origin: true });

export const generatePDF = functions
  .runWith(runtimeOpts)
  // .region('europe-west1')
  .https.onRequest(async (request: any, response: any) => {
    // cors(request, response, async () => {
    console.log(7);

    const hostname = request.hostname;

    let url = '';
    if (hostname === 'localhost') {
      url = 'http://localhost:5000';
    } else {
      url = 'https://myapp.firebaseapp.com';
    }

    const puppeteer = require('puppeteer');

    console.log('launch puppeteer');

    const browser = await puppeteer.launch({
      args: ['--no-sandbox', '--disable-setuid-sandbox'],
    });
    // debug: {headless: false}

    console.log('new page');

    const page = await browser.newPage();

    console.log('goto');

    await page
      .goto(`${url}/report/A3p71Fl5GD98Sjks5BJg`)
      .catch((error: any) => {
        console.log(error);
        return response.send('Timeout1');
      });

    console.log('waitFor');

    // await page.waitFor(10000).catch((error: any) => {
    //   console.log(error);
    //   return response.send('Timeout2');
    // });

    await new Promise(resolve => setTimeout(resolve, 5000));

    // await page.waitForNavigation({
    //   waitUntil: 'networkidle0',
    // });

    // Wait for element to render
    // await page.waitForSelector('#end');

    // await page.waitFor(10000);

    console.log('create pdf');

    const pdf = await page.pdf({
      format: 'A4',
    });

    console.log('close browser');

    await browser.close();

    // response.setHeader('Content-Disposition', 'attachment; filename=customfilename.pdf');
    response.setHeader('Content-Disposition', 'filename=customfilename.pdf');
    return response.type('application/pdf').send(pdf);
    // });
  });

export const helloWorld = functions.https.onRequest(
  async (request: any, response: any) => {
    await new Promise(resolve => setTimeout(resolve, 5000));
    response.send('Hello from Firebase!');
  },
);

// function delay(ms: number) {
//   return new Promise(resolve => setTimeout(resolve, ms));
// }

package.json:

{
  "name": "functions",
  "scripts": {
    "lint": "tslint --project tsconfig.json",
    "build": "tsc",
    "serve": "npm run build && firebase serve",
    "shell": "npm run build && firebase functions:shell",
    "start": "npm run shell",
    "deploy": "firebase deploy --only functions",
    "logs": "firebase functions:log"
  },
  "engines": {
    "node": "8"
  },
  "main": "lib/index.js",
  "dependencies": {
    "cors": "^2.8.5",
    "firebase-admin": "^8.7.0",
    "firebase-functions": "^3.3.0",
    "puppeteer": "^2.0.0"
  },
  "devDependencies": {
    "tslint": "^5.12.0",
    "typescript": "^3.6.3"
  },
  "private": true
}

tsconfig.json:

{
  "compilerOptions": {
    "module": "commonjs",
    "noImplicitReturns": true,
    "noUnusedLocals": true,
    "outDir": "lib",
    "sourceMap": true,
    "strict": true,
    "target": "es2017",
    "lib": ["dom"]
  },
  "compileOnSave": true,
  "include": ["src"]
}

最佳答案

您应该在您的函数之外导入 puppeteer,以便 firebase 可以重用它。您也不需要创建超时,但可以使用 await page.waitFor(5000); 代替。我试图为您的用例创建一个最小示例。如果您仍然遇到错误,请转到您的 firebase 函数控制台并检查日志,它们应该会告诉您出了什么问题。

也有可能您没有在您的 firebase 帐户上启用计费 - 在这种情况下,您的功能无法访问第 3 方主机。

import * as functions from 'firebase-functions';
import * as puppeteer from 'puppeteer';

export const generatePDF = functions
    .runWith({ timeoutSeconds: 30, memory: "1GB" })
    .https.onRequest(async (request, response) => {

        const url = 'https://www.yoururl.com/';
        const browser = await puppeteer.launch({ headless: true, args: ['--no-sandbox'] });

        const page = await browser.newPage();
        await page.goto(url);
        await page.waitFor(5000);

        const pdf = await page.pdf({
            format: 'A4',
        });

        await browser.close();

        response.setHeader('Content-Disposition', 'filename=customfilename.pdf');
        return response.type('application/pdf').send(pdf);
    });

关于javascript - Puppeteer 等待页面和 setTimeout 在 Firebase 云功能中不起作用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58718572/

相关文章:

javascript - 计算输入字段的动态数量之间的百分比

javascript - 如何使用 angularjs 在 Kendo 网格过滤器文本框中应用电话号码掩码?

typescript - 扩展现有对象的属性,例如 TypeScript 中的 Date

javascript - 如何在 rxjs 中做链式序列

Firebase Cloud Firestore 在 Flutter 中获取 map 数组

java - boolean 值和 Firebase 数据库

ios - 从 firebase 获取的图像在将它们添加到 tableViewCells 的过程中被复制了吗?

javascript - 如何仅在 WooCommerce 结帐页面中启用 Bootstrap css

javascript - Ember.js - 为目标应用程序创建动态 filterProperty 值

html - Angular - undefined variable 的字符串插值