使用Puppeteer在客户端生成PDF

时间:2019-05-27 14:13:30

标签: node.js express puppeteer

我正在努力让Puppeteer在浏览器中下载文件。我目前可以将其保存在Cloud9上的本地文件中,但是我想单击一个PDF下载按钮,然后将其下载到Chrome中。

我尝试将page.pdf保存为变量,但没有成功。我也尝试过打开本地保存的文件,但是我也无法使它正常工作。

var express = require("express");
var puppeteer = require("puppeteer");

module.exports = function pdf(url, req) {(async () => {
      var browser = await puppeteer.launch();
      var page = await browser.newPage();
      await page.goto('https://node-and-mysql-mbegg.c9users.io/clients/'+req.params.id+'/reports/monthlyreport/'+req.params.marketplace+'/'+req.params.month, {waitUntil: 'networkidle2'});
      await page.pdf({path: 'public/temp/Performance Report -'+req.params.month+'.pdf', format: 'A4', landscape: true, printBackground: true});

      await browser.close();
    })();
}

///Print PDF route
router.get("/clients/:id/reports/monthlyreport/:marketplace/:month/pdf", function(req, res) {
    var url = "/clients/"+req.params.id+"/reports/monthlyreport/"+req.params.marketplace+"/"+req.params.month
    pdf(url, req);
    res.contentType("application/pdf");
    res.send(pdf);;
});

我知道res.send(pdf)需要将page.pdf()保存到变量并返回。我只是没有将其从路线中删除。

当我将page.pdf()保存到一个变量中时,会发生什么情况,就是我只得到一个空白文件,而不是PDF,而它似乎只是一个空白缓冲区或其他东西。我不知道自己在做错什么,无法在chrome浏览器中下载文件。

2 个答案:

答案 0 :(得分:0)

///  Async/await
router.get("/clients/:id/reports/monthlyreport/:marketplace/:month/pdf", async function(req, res) {
    var url = "/clients/"+req.params.id+"/reports/monthlyreport/"+req.params.marketplace+"/"+req.params.month
    let pdfData = await pdf(url, req);
    res.contentType("application/pdf");
    res.send(pdfData);
});
///  promise
router.get("/clients/:id/reports/monthlyreport/:marketplace/:month/pdf", async function(req, res) {
    var url = "/clients/"+req.params.id+"/reports/monthlyreport/"+req.params.marketplace+"/"+req.params.month
    pdf(url, req).then((pdfData )=>{
        res.contentType("application/pdf");
        res.send(pdfData);
    });
});

您都没有等待过程完成。您还发送了函数,而不是结果。

答案 1 :(得分:0)

虽然在pdf函数中您似乎正在等待每个puppeteer操作,但实际上您并不是在等待快速路由中对pdf函数的调用。此外,pdf函数现在不返回任何内容!您需要对程序进行以下修改:

  1. pdf函数应返回将生成的PDF保存到的文件名。当您使用它时,也可以摆脱IIFE,这不是必需的,只需将外部函数声明为async
  2. 在路由功能中,程序应等待pdf(...)调用返回文件名。这可以通过使用Promise或等待来完成。如果首选使用await,则外部函数应标记为异步。
  3. sendFile对象上的express提供的response函数应用于将生成的PDF文件发送给客户端。请注意,res.sendFile需要文件的绝对路径。

以下是实现这些功能的程序的修改版本。

const express = require("express");
const puppeteer = require("puppeteer");
const path = require('path');

module.exports = async function pdf(url, req) {
    const filename = `public/temp/Performance Report -${req.params.month}.pdf`;
    const browser = await puppeteer.launch();
    const page = await browser.newPage();

    await page.goto('https://node-and-mysql-mbegg.c9users.io/clients/'+req.params.id+'/reports/monthlyreport/'+req.params.marketplace+'/'+req.params.month, {waitUntil: 'networkidle2'});
    await page.pdf({path: filename, format: 'A4', landscape: true, printBackground: true});

    await browser.close();
    return filename;
}

///Print PDF route
router.get("/clients/:id/reports/monthlyreport/:marketplace/:month/pdf", async function(req, res) {
    var url = "/clients/"+req.params.id+"/reports/monthlyreport/"+req.params.marketplace+"/"+req.params.month

    const filename = await pdf(url, req);
    res.contentType("application/pdf");
    res.sendFile(path.join(__dirname, filename)); // if 'public/temp/...' path is not relative to cur dir, make relevant change here.
});