首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >速递/链接:从EJS模板生成PDF并作为响应发送

速递/链接:从EJS模板生成PDF并作为响应发送
EN

Stack Overflow用户
提问于 2022-10-30 17:43:55
回答 1查看 117关注 0票数 0

此用户使用Puppeteer代码的路由:

代码语言:javascript
运行
复制
Router.get('/generate_invoice', (req, res) => {


    const userData = req.session.user;
    res.render("./patientpanel/invoice", { user: userData });

    (async () => {
        // launch a new chrome instance
        const browser = await puppeteer.launch({
            headless: true
        });

        const page = await browser.newPage();
        const filePathName = path.resolve(__dirname, '../views/patientpanel/invoice.ejs');

        const html = fs.readFileSync(filePathName, 'utf8')
        await page.goto("http://localhost:5000/generate_invoice" + html);
        await page.setContent(html, {
            waitUntil: 'domcontentloaded'
        });
        const pdfBuffer = await page.pdf({
            format: 'A4'
        });

        // or a .pdf file
        await page.pdf({ path: "./user.pdf", format: pdfBuffer });
        await browser.close()
    })();
});

PDF文件生成成功,但它显示了EJS模板,因为它没有任何适当的格式和数据,我通过上面的路由器呈现。

EJS模板代码:

代码语言:javascript
运行
复制
<tr class="information">
    <td colspan="2">
        <table>
            <tr>
                <td>
                    Name: <%- user.firstname %>
                    <%- user.lastname %><br />
                    Email: <%- user.email %><br />
                    Mobile No. : <%- user.mob %>
                </td>
            </tr>
        </table>
    </td>
</tr>

EN

回答 1

Stack Overflow用户

发布于 2022-11-04 20:33:35

基本的误解似乎是熟悉与Express (例如res.render())结合在一起的EJS,而不是独立的。EJS提供了分别处理文件和普通字符串的renderFilerender方法。您想要使用这些来准备HTML,然后将其放入Puppeteer,PDF'd,然后作为响应发送。

下面是处理请求的基本工作流:

代码语言:javascript
运行
复制
.-------------------.
| EJS template file |
`-------------------`
       |
[ejs.renderFile]
       |
       v
.-------------.
| HTML string |
`-------------`
       |
[page.setContent]
       |
       v
.-------------.
| browser tab |
`-------------`
       |
   [page.pdf]
       |
       v
.------------.
| PDF buffer |
`------------`
       |
   [res.send]
       |
       v
.----------.
| response |
`----------`

下面是一个您可以使用的完整示例(我简化了路径,以便在没有文件夹结构的情况下更容易地复制;模板位于与服务器代码相同的目录中):

代码语言:javascript
运行
复制
const ejs = require("ejs"); // 3.1.8
const express = require("express"); // ^4.18.1
const puppeteer = require("puppeteer"); // ^19.1.0

express()
.get("/generate-invoice", (req, res) => {
  const userData = { // for example
    firstname: "linus",
    lastname: "torvalds",
    email: "foo@bar.com",
    mob: "900-900-9000"
  };

  let browser;
  (async () => {
    browser = await puppeteer.launch();
    const [page] = await browser.pages();
    const html = await ejs.renderFile("invoice.ejs", {user: userData});
    await page.setContent(html);
    const pdf = await page.pdf({format: "A4"});
    res.contentType("application/pdf");

    // optionally:
    res.setHeader(
      "Content-Disposition",
      "attachment; filename=invoice.pdf"
    );

    res.send(pdf);
  })()
    .catch(err => {
      console.error(err);
      res.sendStatus(500);
    }) 
    .finally(() => browser?.close());
})
.listen(3000);

导航到http://localhost:3000/generate-invoice以进行测试。

您可以使用ejs.render()fs.readFile在应用程序开始时立即将文件提取进来,在每个ejs.renderFile请求上保存一个额外的文件。

顺便说一句,在每个请求上启动浏览器有点麻烦,所以您可以考虑使用一个浏览器和多个页面。有关潜在的方法,请参见this answer

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/74255357

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档