Итак, я написал небольшой код для преобразования html строка в pdf с помощью библиотеки Wkhtmltopdf.
Вот код, который я написал:
index.js
const express = require('express')
const app = express()
app.use(express.json())
const port = 3000
const compiledHtml = '<h1> This is testing </h1>'
app.post('/gc', async (req, res) => {
wkhtmltopdf(compiledHtml, {
pageSize: 'A4',
orientation: 'Landscape',
marginLeft: '1mm',
marginTop: '1mm'
}).pipe(fs.createWriteStream('out.pdf')) //--->(A)
console.info('All done')
res.send(compiledHtml)
})
app.listen(port, () => console.info(`Example app listening on port ${port}!`))
В этом коде я создал ОТДЫХА вызов, СООБЩЕНИЕ в природе, который создает PDF-файл и сохраняет его в файле с именем выход.pdf (уравнение (A) выше) в той же папке, где работает скрипт.
Но на самом деле я хочу сгенерировать пдф в объем памяти, получить буфер того же самого и вернуть буфер обратно клиенту, чтобы браузер начал загрузку файла, у меня также есть код для этого, вот код для возврата буфер в отклик в выражать
фрагмент
......
......
res.writeHead(200, {
'Content-Type': 'application/pdf',
'Content-disposition': 'attachment;filename=certificate.pdf',
'Content-Length': buffer.length,
})
res.end(buffer)
......
......
С помощью приведенного выше кода мы можем записать двоичные данные обратно клиенту, которые он может сохранить в любом месте.
Но основная проблема заключается в том, как мне получить буфер создаваемого файла.
Пожалуйста, пролейте немного света, удачного кодирования :)





Я бы предложил просто передать вывод из wkhtmltopdf в объект res, это позволяет избежать полного создания буфера.
const express = require('express')
const app = express()
app.use(express.json())
const port = 3000
const compiledHtml = '<h1> This is testing </h1>'
app.post('/gc', async (req, res) => {
res.writeHead(200, {
'Content-Type': 'application/pdf',
'Content-disposition': 'attachment;filename=certificate.pdf',
});
wkhtmltopdf(compiledHtml, {
pageSize: 'A4',
orientation: 'Landscape',
marginLeft: '1mm',
marginTop: '1mm'
}).pipe(res)
console.info('All done')
});
app.listen(port, () => console.info(`Example app listening on port ${port}!`))
Вам не нужно устанавливать заголовок длины содержимого, заголовок передачи-кодирования будет установлен на фрагменты, клиент сможет загрузить файл.
Итак, вот решение изменения буферизованного потока на асинхронное поведение ожидания, вот общее решение, которое я сделал:
ОТКАЗ ОТ ОТВЕТСТВЕННОСТИ: ЭТО НЕ ХОРОШАЯ ПРАКТИКА ДЛЯ БОЛЬШИХ ПОТОКОВ, НО МОЖЕТ ИСПОЛЬЗОВАТЬСЯ, ЕСЛИ ВЫ ЗНАЕТЕ, ЧТО РЕЗУЛЬТАТИВНЫЙ БУФЕР БУДЕТ НЕСКОЛЬКО КБ
const streamToBuffer = (streamObjectToRead) => {
const chunks = []
return new Promise((resolve, reject) => {
streamObjectToRead
.on('data', chunk => chunks.push(chunk))
.on('end', () => resolve(Buffer.concat(chunks)))
.on('error', err => reject(err))
})
}
Теперь, чтобы использовать это, вы можете использовать так:
const someAsyncFunction = async () => {
......
...... //some code
const stream = <FUNCTION THAT RETURNS A STREAM> // like wkhtmltopdf(compiledHtml, optionsObject)
const fullBufferAfterReadingFullStream = await streamToBuffer(stream)
..... // do whatever you want to do with that buffer, eg: Writing to file, sending back to response in express framework.
}
Спасибо и удачного кодирования :)
В этом случае я не могу установить
'Content-Length': buffer.length,, так как понятия не имею, что это будет.