Puppeteer PDF从云中生成空白页,与邮递员一起工作.有什么想法吗?



我花了几天时间搜索、调整、部署、记录......没有任何效果。我希望这只是我的一个愚蠢的疏忽,没有埋葬在这个项目中的人可以向我指出这一点。

我正在尝试使用 Puppeteer 从托管的 Node.js Express API 端点创建 PDF,该端点由 Firebase Cloud Functions 托管,作为前端 Vue 应用程序的微服务。我正在使用 Axios 发出发布请求并在正文中传递 HTML 字符串。使用正文解析器,我可以将数据分配给变量。

const express = require('express');
const functions = require('firebase-functions');
const puppeteer = require('puppeteer');
const bodyParser = require('body-parser');
const cors = require('cors');
const app = express();
const corsConfig = {
origin: true,
credentials: true,
}
app.use(cors(corsConfig));
app.options('*', cors(corsConfig));
app.all('*', async (request, response, next) => {
response.locals.browser = await puppeteer.launch({
dumpio: true,
headless: true,
args: ['--no-sandbox', '--disable-setuid-sandbox']
});
next();
});
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
app.post('/pdf', async (request, response) => {
const html = request.body.html;
//console.log(typeof html, html);
if (!html) {
return response.status(400).send(
'Something happened so I cannot create your PDF right now.');
}
const browser = response.locals.browser;
const page = await browser.newPage();
//await page.goto(`data:text/html,${encodeURIComponent(html)}`, { waitUntil: 'networkidle0' });
await page.setContent(html, { waitUntil: ['domcontentloaded', 'load', "networkidle0"] }, { timeout: 0 });
await page.addStyleTag({ path: 'style.css' });
const pdf = await page.pdf({
format: 'Letter',
printBackground: true,
});
//console.log(pdf);
response.set({ 'Content-Type': 'application/pdf', 'Content-Length': pdf.length });
response.send(pdf);
await browser.close();
return pdf;
});
const opts = { memory: '2GB', timeoutSeconds: 60 };
exports.pdf = functions.runWith(opts).https.onRequest(app);

控制台日志记录显示变量是一个字符串,并且标记看起来不错。当我用它来page.setContent(html, {waitUntil: 'networkidle0'}),然后page.pdf(),我得到一个包含 3 个空白页的 PDF。函数日志的屏幕截图

我已经尝试了整个page.goto的事情和相同的结果。如果我将 HTML 字符串更改为更短的内容,例如'<h1>Hello World</h1>'(尝试作为变量和实际字符串(,我会得到一个带有 1 个空白页的 PDF。这让我相信它理解我,只是不渲染。我将所有 id 更改为类,并将十六进制颜色更改为 RGB 以避免 # 冲突(我读过它们可能会搞砸事情(。

我尝试使用车把模板,只在请求正文中发送 JSON 数据,但这也没有用。现在,如果我使用 postman 并在正文中使用 HTML 字符串发送请求,我会得到我正在寻找的内容。这样做的缺点是它没有 AXIOS 代码片段供我在应用程序中使用和复制结果。

这是前端

savePDF() {
this.getPDF()
.then(response => {
const blob = new Blob([response.data], { type: "application/pdf" });
const link = document.createElement("a");
link.href = window.URL.createObjectURL(blob);
link.target = "_blank";
link.click();
})
.catch(err => alert(err));
},
async getPDF() {
const html = document.querySelector(".wrapper").outerHTML;
axios.defaults.withCredentials = true;
const pdf = await axios
.post("MYENDPOINTURL/pdf", { html })
.then(
response => {
return response;
},
error => {
alert(error);
}
);
return pdf;
}

更新我放弃了 Axios 并使用了获取帖子请求......它奏效了!有了这个,我为此更改了getPDF和savePDF前端函数(服务器端保持不变(:

async savePDF() {
const html = document.querySelector(".wrapper").outerHTML;
var myHeaders = new Headers();
myHeaders.append("Content-Type", "application/x-www-form-urlencoded");
var urlencoded = new URLSearchParams();
urlencoded.append("html", html);
var requestOptions = {
method: "POST",
headers: myHeaders,
body: urlencoded,
redirect: "follow"
};
fetch("MYENDPOINTURL/pdf", requestOptions)
.then(response => response.blob())
.then(result => {
const blob = new Blob([result], { type: "application/pdf" });
const link = document.createElement("a");
link.href = window.URL.createObjectURL(blob);
link.target = "_blank";
//link.download = `${this.propertyInfo.property}-${this.propertyInfo.workType}.pdf`;
link.click();
})
.catch(error => alert("error", error));
}

我仍然对让 Axios 工作感兴趣,但将其切换为获取,现在一切都已启动并运行。

const html = document.querySelector(".wrapper").outerHTML;
var myHeaders = new Headers();
myHeaders.append("Content-Type", "application/x-www-form-urlencoded");
var urlencoded = new URLSearchParams();
urlencoded.append("html", html);
var requestOptions = {
method: "POST",
headers: myHeaders,
body: urlencoded,
redirect: "follow"
};
fetch("MYENDPOINTURL/pdf", requestOptions)
.then(response => response.blob())
.then(result => {
const blob = new Blob([result], { type: "application/pdf" });
const link = document.createElement("a");
link.href = window.URL.createObjectURL(blob);
link.target = "_blank";
//link.download = `${this.propertyInfo.property}-${this.propertyInfo.workType}.pdf`;
link.click();
})
.catch(error => alert("error", error));

我参加聚会很晚了,但如果有人对使用 Axios 进行这项工作感兴趣,只需在您的请求正文中添加{responseType: "blob"}即可。

例:

const res = await api.get(`/my-pdf`, { responseType: "blob" });
return res.data

将正确生成 Blob。

最新更新