我正在尝试加载我在 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/