Узел / Экспресс: нет загрузки в stream.pipe ()

#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();
        }
    });