#node.js #express #download #streaming
#node.js #экспресс #Скачать #потоковая передача
Вопрос:
Есть ли какой-нибудь способ принудительно загрузить, когда я передаю поток в ответ? Если я загляну в Chrome tools, я увижу, что ответ в порядке, с прекрасными заголовками:
HTTP/1.1 200 OK
Server: Cowboy
Connection: keep-alive
X-Powered-By: Express
Content-Type: application/pdf
Date: Mon, 10 Oct 2016 20:22:51 GMT
Transfer-Encoding: chunked
Via: 1.1 vegur
Request Headers
view source
Я даже вижу код файла pdf в подробном ответе, но загрузка файла не инициируется. Может быть, я что-то пропустил?
Мой код на маршруте выглядит так:
router.post('/reports/create', access.Regular, function (req, res, next) {
...
pdf.create(html).toBuffer(function(err, buffer){
res.writeHead(200, {
'Content-Type': 'application/pdf',
'Content-Disposition': 'attachment; filename=some_file.pdf',
'Content-Length': buffer.length
});
res.end(buffer)
});
});
Комментарии:
1. Какой у вас код? Как вы подключаетесь к серверу?
2. Я использую обычный экспресс-шаблон
app.post(...)
, как в комментарии ниже3. Я имею в виду, как вы подключаетесь в браузере? Используете ли вы что-то вроде
XMLHttpRequest
$.ajax
илиfetch
для отправки вашего запроса?4. Полимерная железная форма (на самом деле это похоже на XMLHttpRequest)
5. Я думаю, что @Frxmstrem имел в виду, что вы должны включить как можно больше кода запроса вашего клиента, чтобы люди могли лучше ответить на вопрос.
Ответ №1:
Вам нужно добавить Content-Disposition
заголовок, чтобы сообщить браузеру, что к нему прикреплен контент, который необходимо загрузить.
app.get('/:filename', (req, res) => {
// Do whatever work to retrieve file and contents
// Set Content-Disposition Header on the response
// filename is the name of the file the browser needs to download when
// receiving the response to this particular request
res.setHeader('Content-Disposition', `attachment; filename=${req.params.filename}`);
// stream the fileContent back to the requester
return res.end(fileContent)
});
Комментарии:
1. У меня есть поток или буфер, а не определенный файл
2. @AlexNasonov, в моем примере fileContent — это поток или буфер, но суть примера в том, что
Content-Disposition
в вашем ответе отсутствует заголовок. По сути, этот заголовок сообщает браузеру, что вы вернули поток / буфер данных, и он должен быть загружен с именем внутриfilename
значения заголовка.3.
router.post('/reports/create', access.Regular, function (req, res, next) { res.setHeader('Content-type', 'application/pdf'); res.setHeader('Content-Disposition', `attachment; filename=file.pdf`); ... pdf.create(html, options).toStream(function(err, stream){ stream.pipe(res); }); });
— та же проблема — я вижу данные в ответ через консоль, но файл не загружается4. Даже такой простой код, как:
res.writeHead(200, { 'Content-Type': 'application/txt', 'Content-Disposition': 'attachment; filename=some_file.txt' }); var buffer = Buffer.from('string'); res.end(buffer);
не работает нормально ((
Ответ №2:
для меня это работает так:
var html = '<h1>Hello World</h1>';
let options = {
format: 'Letter',
border: '1cm'
};
pdf.create(html, options).toBuffer(function (err, Buffer) {
if (err) {
res.json({
data: 'error PDF'
})
} else {
res.set({
'Content-Disposition': 'attachment; filename=test.pdf',
'Content-Type': 'application/pdf; charset=utf-8'
});
res.write(Buffer);
res.end();
}
});