Я провел дни в поисках, настройках, развертывании, регистрации ... Ничего не помогло. Я надеюсь, что это просто глупое упущение с моей стороны, и тот, кто не похоронен в этом проекте, может просто указать мне на это.
Я пытаюсь использовать Puppeteer для создания PDF из Node.js Express Конечная точка API, размещенная с Firebase Cloud Functions в качестве микросервиса для внешнего интерфейса Vue приложения. Я использую Ax ios для отправки запроса и передаю строку HTML в теле. С помощью bodyparser я могу присвоить данные переменной.
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()
, я получаю PDF с 3 пустыми страницами. Снимок экрана журнала функций
Я испробовал целую вещь page.goto
и те же результаты. Если я изменю строку HTML на что-то намного более короткое, например '<h1>Hello World</h1>'
(пробовал как переменную, так и фактическую строку), я получу PDF с 1 пустой страницей. Это заставляет меня верить, что оно понимает меня, а не рендеринг. Я изменил все идентификаторы на класс, а шестнадцатеричные цвета на RGB, чтобы избежать # конфликтов (я читал, что они могут все испортить).
Я пытался использовать шаблон руля и отправлять только JSON данные в тело запроса, и это тоже не сработало. Теперь, если я использую почтальон и отправляю запрос со строкой HTML в теле, я получаю именно то, что ищу. Недостатком этого является то, что у меня нет фрагментов AX IOS, чтобы я мог использовать и копировать результаты в моем приложении.
Вот интерфейс
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;
}
ОБНОВЛЕНИЕ Я бросил Ax ios и использовал запрос на извлечение сообщений ... и это сработало! После этого я изменил функции интерфейса 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));
}