Problema de búfer estándar usando el nodo child_process

92

Estoy tratando de ejecutar curl usando el nodo child_process para obtener un archivo JSON (aproximadamente 220Ko) de una carpeta compartida en una red local. Pero en realidad devuelve un problema de búfer que no puedo resolver. Aquí está mi código:

var exec = require('child_process').exec;

var execute = function(command, callback){
    exec(command, function(error, stdout, stderr){ callback(error, stdout); });
};

execute("curl http://" + ip + "/file.json", function(err, json, outerr) {
    if(err) throw err;
    console.log(json);
})

Y aquí está el error que obtengo:

if(err) throw err;
          ^
Error: stdout maxBuffer exceeded.
    at Socket.<anonymous> (child_process.js:678:13)
    at Socket.EventEmitter.emit (events.js:95:17)
    at Socket.<anonymous> (_stream_readable.js:746:14)
    at Socket.EventEmitter.emit (events.js:92:17)
    at emitReadable_ (_stream_readable.js:408:10)
    at emitReadable (_stream_readable.js:404:5)
    at readableAddChunk (_stream_readable.js:165:9)
    at Socket.Readable.push (_stream_readable.js:127:10)
    at Pipe.onread (net.js:526:21)
Yonnaled
fuente

Respuestas:

161

Debe usar y configurar la maxBufferopción al usar child_process.exec. De la documentación :

maxBuffer especifica la mayor cantidad de datos permitidos en stdout o stderr; si se excede este valor, el proceso hijo se mata.

La documentación también indica que el valor predeterminado de maxBufferes 200 KB.

Como ejemplo, el tamaño máximo del búfer se aumenta a 500 KB en el siguiente código:

var execute = function(command, callback){
    exec(command, {maxBuffer: 1024 * 500}, function(error, stdout, stderr){ callback(error, stdout); });
};

Además, es posible que desee leer sobre http.getpara ver si es capaz de lograr lo que está tratando de hacer.

Tim Cooper
fuente
Esto resolvió mi problema, ¡gracias! La carpeta compartida está en realidad bajo el protocolo webdav que requiere una autenticación implícita, por eso estoy usando curl que lo maneja muy fácilmente concurl --digest http://login:password@" + ip + "/webdav/file.json
Yonnaled
Este valor predeterminado es ridículamente pequeño. Esta es la segunda vez que me muerde esto de una manera difícil de encontrar.
jlh
3
El valor predeterminado ahora es 1 MB @jlh, nodejs.org/api/…
Carlos
57

Tuve un problema similar y lo solucioné pasando de ejecutivo a spawn:

var child = process.spawn('<process>', [<arg1>, <arg2>]);

child.stdout.on('data', function (data) {
  console.log('stdout: ' + data);
});

child.stderr.on('data', function (data) {
  console.log('stderr: ' + data);
});

child.on('close', function (code) {
    console.log('child process exited with code ' + code);
});
lsampaio
fuente
10
Esta parece ser la solución más apropiada de las dos
Hashbrown
1
Esta respuesta no es necesariamente la más adecuada. Creo que la salida de la consola en la pregunta podría ser solo un ejemplo. Casi nadie buscaría un archivo de 200 KB para lanzarlo a la consola. Sin embargo, si process.execse usa en cosas como herramientas CLI, entonces sí, cambiar a spawndebería ser el camino a seguir.
Pavel Gatilov
1
wow ... spawn es genial. Ni siquiera es usar devoluciones de llamada o promesas ... solo eventos. Eso podría ser realmente útil para transmitir stdout a la consola. @Pavel Gatilov, eso es exactamente lo que estamos haciendo. A FFMpeg le gusta mostrar el progreso cada segundo ... lo que afecta el búfer
Ray Foss