Как вернуть сгенерированный PDF из приложения ExpressJS? - PullRequest
0 голосов
/ 17 марта 2020

Я пытаюсь получить приложение Express для возврата сгенерированного PDF. Согласно этому ответу , я пытаюсь использовать библиотеку jsPDF с некоторыми поддельными глобалами. Кроме того, путаница заключается в том, что данные извлекаются из источника Postgres.

Я никогда раньше не использовал .blob(), и я подозреваю, что по этой причине я не получаю ответ. Есть ли что-то очевидное, чего мне не хватает?

const express = require('express')
const bodyParser = require('body-parser')
const SQL = require('sql-template-strings')
const { Client } = require('pg')
const dbConfig = require('../db')

const FormRouter = express.Router()

function saveFormAsPDF(form) {
  global.window = {
    document: {
      createElementNS: () => {
        return {}
      },
    },
  }
  global.navigator = {}
  global.html2pdf = {}
  global.btoa = () => {}

  const jsPDF = require('jspdf') // wrapped by the fake globals
  const doc = new jsPDF({
    orientation: 'landscape',
    format: 'a4',
  })

  doc.setFontSize(24)
  doc.text('Form: ' + (form.identifier || 'Awaiting Retrieval'), 20, 20)
  var data = doc.output()

  delete global.window
  delete global.html2pdf
  delete global.navigator
  delete global.btoa
  return data
}

const getFormAsPDFByIdRoute = (req, res) => {
  const client = new Client(dbConfig)
  client.connect()
  return client
    .query(SQL`SELECT * FROM forms WHERE id = ${req.params.id}`)
    .then(result => {
      res
        .status(result.rowCount === 0 ? 404 : 200)
        .set({ 'content-type': 'application/pdf' })
        .blob( saveFormAsPDF(result.rows[0]) )
    })
    .then(() => client.end())
}

FormRouter.route('/id/:id').get(getFormsByIdRoute)

FormRouter.route('/pdf/:id').get(getFormAsPDFByIdRoute)

exports.FormRouter = FormRouter

1 Ответ

4 голосов
/ 20 марта 2020

Одна вещь, которую я заметил в вашем коде, заключалась в том, что вы не ожидаете разрешения вызова client.connect(). Если вы не передадите обратный вызов функции, возвращается обещание, которое вы должны ждать.

Относительно генерации PDF-файлов:

У меня было аналогичное требование для генерации PDF-файлов из html некоторое время go и я в итоге использовал html-pdf библиотеку .

Используя эту библиотеку, вы просто создадите поток преобразования и направите его в ответ. Примерно так (все еще требуется правильная обработка ошибок):

const html2pdf = require('html-pdf');

const getFormAsPDFByIdRoute = async(req, res) => {
    const client = new Client(dbConfig);
    await client.connect();
    const result = await client.query(SQL `SELECT * FROM forms WHERE id = ${req.params.id}`);
    if (!result.rowCount) {
        return res.status(404).end();
    }
    const stream = await createHtlm2PdfStream(result.rows[0]);
    res.contentType('application/pdf');
    stream.pipe(res);
}

function createHtlm2PdfStream(html) {
    return new Promise((resolve, reject) => {
        html2pdf.create(html).toStream((err, stream) => {
            if (err) {
                return reject(err);
            }
            resolve(stream);
        });
    });
}

EDIT : как я предполагал, pdf должен был быть сгенерирован из html, но вместо этого должен быть создан pdf ручное использование pdfkit кажется правильным выбором:

const PDFDocument = require('pdfkit');

const getFormAsPDFByIdRoute = async(req, res) => {
    const client = new Client(dbConfig);
    await client.connect();
    const result = await client.query(SQL `SELECT * FROM forms WHERE id = ${req.params.id}`);
    if (!result.rowCount) {
        return res.status(404).end();
    }
    const doc = new PDFDocument();
    res.contentType('application/pdf');
    doc.pipe(res);
    // render some text (you can use .font(...) to alter the font style)
    const formContent = result.rows[0];
    doc.text(`Some text with the form id ${formContent.identifier}`, 100, 100);
    doc.end();
}
...