【问题标题】:Generate PDF with puppeteer without save it使用 puppeteer 生成 PDF 而不保存
【发布时间】:2019-04-09 18:22:47
【问题描述】:

我有一个用 node.js 编写的 API,托管在 heroku 上,我的前端应用程序是用 Vue.js 编写的,它在 hostinger 上。我想知道是否可以使用 puppeteer 生成 PDF 文件并立即将其发送到前端客户端而不先将其保存到磁盘?如果是的话,你能给我举个例子吗?

目前我的功能是这样的:

exports.gerarPDFAvaliacao = async (dadosAvaliacao) => {
    try {
        const compile = async (fileName, data) => {

            const filePath = path.join(process.cwd(), 'src/templates/client/operation/', `${fileName}.hbs`);
            const html = await fs.readFile(filePath, 'utf-8');
            return await hbs.compile(html)(data);
        }

        const browser = await puppeteer.launch();
        const page = await browser.newPage();

        let content = await compile('avaliations', dadosAvaliacao);

        await page.goto(`data:text/html,${content}`, { waitUntil: 'networkidle0' });
        await page.emulateMedia('screen');
        await page.pdf({
            path: 'src/dist/pdf/' + dadosAvaliacao.arquivo + '.pdf',
            format: 'A4',
            printBackground: true
        })
        await browser.close();

        return dadosAvaliacao.arquivo + '.pdf';
    } catch (error) {
        console.log('Errors => ', error);
    }
};

【问题讨论】:

    标签: node.js vue.js puppeteer


    【解决方案1】:

    根据official documentation,如果您不提供路径,文件将不会保存到磁盘。

    page.pdf(选项): 可能具有以下属性的选项对象: path 保存 PDF 的文件路径。如果 path 是相对路径,则相对于当前工作目录进行解析。如果没有提供路径,PDF 将不会保存到磁盘。

    这意味着它应该返回类似于缓冲区或生成文件的二进制表示的东西。您只需将其返回或通过管道将其返回到响应中,具体取决于您使用的框架。

    这只是将 pdf 输出到控制台:

    const browser = await puppeteer.launch();
    const page = await browser.newPage();
    await page.goto('https://example.com');
    
    console.log(await page.content());
    const pdf = await page.pdf();
    
    await browser.close();
    console.log(pdf) // maybe do response(pdf).type('x-pdf')
    

    编辑:这是一个使用 express 和 puppeteer 的完整示例,它直接在内存中返回 pdf 内容。它在 runkit 上运行,所以我认为同样的限制也适用(也许更多)。如果您导航到示例具有的公共端点,您可以看到浏览器如何检测到它是一个 pdf 文件并正确呈现它。

    代码

    const puppeteer = require ('puppeteer');
    const express = require('express');
    var app = express(exports);
    const browser = await puppeteer.launch();
    
    const main = async () => {
    
        const page = await browser.newPage();
        await page.goto('https://example.com');
    
        const pdf = await page.pdf();
        return pdf;
     }
    
    
    app.get('/', async function (req, res) {
            const pdf = await main();
            res.contentType("application/pdf");
            res.send(pdf);
    });
    
    app.listen(3000, function(){ console.log('Listening on 3000') });
    

    【讨论】:

    • Danielo515,我已经编辑了我的问题并插入了我的函数。如您所见,我使用车把生成模板,然后将其传递给 puppeteer 以创建 pdf 文件。然后最后我把文件的路径返回到前面。
    • 是的,你可以这样做。但正如我在示例中所展示的,如果您不提供路径,则该文件将在内存中生成,您可以将其保存到一个变量中,然后以正确的编码返回它。两种方法都可以,但您要求的方法不需要将文件保存到磁盘。
    • 多亏了你,我快到了。现在,我可以将缓冲区传递到我的前端,但我不知道如何在前端应用程序(vuejs)中将此缓冲区呈现为 pdf 文件! =(
    • 如果您根据从服务器返回的 mime 类型触发前端应用程序的获取,浏览器可能会自动下载文件。如果您使用的是 express,那么在执行 res(content) 之前,它可能就像 res.header('Content-type', 'application/pdf'); 一样简单。如果这不起作用,您始终可以通过动态创建链接在客户端下载为 blob。这是我用于非常大的 CSV 文件的示例:stackoverflow.com/a/31438726/1734815
    • 非常感谢您的关注,Danielo。我已经解决了将缓冲区更改为 base64 的问题。因此,我收到缓冲区并将其转换为 base64。在前面我创建了一个新的 Blob 并创建了 pdf。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-10-13
    • 2019-04-09
    • 2023-03-28
    • 1970-01-01
    • 1970-01-01
    • 2021-06-19
    • 2020-04-22
    相关资源
    最近更新 更多