Tengo una solicitud de obtención en el nodo que recibe datos de API con éxito.

Cuando canalizo esa respuesta directamente a un archivo como este, funciona, el archivo creado es un pdf válido y legible (como espero recibir de la API).

var http = require('request');
var fs = require('fs');

http.get(
{
  url:'',
  headers:{}
})
.pipe(fs.createWriteStream('./report.pdf'));

Simple, sin embargo, el archivo se corrompe si uso los emisores de eventos de la solicitud de esta manera

  http.get(
{
  url:'',
  headers:{}
})
.on('error', function (err) {
  console.log(err);
})
.on('data', function(data) {
  file += data;
})
.on('end', function() {
    var stream = fs.createWriteStream('./report.pdf');
    stream.write(file, function() {
      stream.end();
    });
});

He intentado todo tipo de escritura de este archivo y siempre termina en un pdf totalmente en blanco; la única vez que el pdf es válido es a través del método pipe.

Cuando registro los eventos en la consola, la secuencia parece ser correcta, es decir, todos los fragmentos recibidos y luego el end se activa al final.

Hace que las cosas sean imposibles de hacer después de la tubería. ¿Qué hace pipe de manera diferente a la corriente de escritura?

0
yoyoma 18 jul. 2017 a las 07:38

2 respuestas

La mejor respuesta

Supongo que inicializas file como una cadena:

var file = '';

Luego, en tu controlador data, le agregas la nueva porción de datos:

file += data;

Sin embargo, esto realiza una conversión implícita a cadenas (codificadas en UTF-8). Si los datos son realmente binarios, como con un PDF, esto invalidará los datos de salida.

En su lugar, desea recopilar los fragmentos data, que son instancias Buffer, y usar Buffer.concat() para concatenar todos esos búferes en un búfer grande (binario):

var file = [];
...
.on('data', function(data) {
  file.push(data);
})
.on('end', function() {
  file = Buffer.concat(file);
  ...
});
7
robertklep 18 jul. 2017 a las 07:49

Si desea hacer algo después de que el archivo termine de escribirse mediante tubería, puede agregar un detector de eventos para finish en el objeto devuelto por tubería.

.pipe(fs.createWriteStream('./report.pdf'))
.on('finish', function done() { /* the file has been written */ });

Fuente: https://nodejs.org/api/stream.html#stream_event_finish

2
iczero 18 jul. 2017 a las 07:19