allisonh allisonh - 1 month ago 12
Node.js Question

Cannot save request data to a file and pipe it to an external request at the same time

I have a node server (using express) that accepts an image as a blob. I curently pipe this directly to an external request, i.e.:

app.post('/process', function(req, res) {
req.pipe({url: '<url-to-external-server>',...},
function(err,response,body) {
//process external response.
}
);
}


This all works fine. Now I would also like to save the data to disk as well, so I add that functionality, so the code now looks like:

app.post('/process', function(req, res) {
var filename = generateUniqueFileName();
var writeStream = fs.createWriteStream(filename);
req.pipe(writeStream);

req.pipe({url: '<url-to-external-server>',...},
function(err,response,body) {
//process external response.
var respData = processBody(
if (!error && response.statusCode == 200) {
res.send(respData);
} else {
// send error.
res.send(...);
}
}
);
}


What happens is that the file is not saved correctly. What am I doing wrong here?

Ben Ben
Answer

One source stream can't be piped to 2 destination streams that way. You need to create a pass through stream (split source stream) to pipe to 2 different destinations. Node's stream module has a pass through for that. Here is the revised code with the pass through:

app.post('/process', function(req, res) {
    // create a pass through stream
    var PassThrough = require('stream').PassThrough;
    var passThroughStream = new PassThrough();

    var filename = generateUniqueFileName();
    var writeStream = fs.createWriteStream(filename);

    req.pipe(passThroughStream);   // split it to this new stream
    passThroughStream.pipe(writeStream); // pipe this to 1st destination

    // now pipe it 2nd destination 
    req.pipe({url: '<url-to-external-server>',...},
      function(err,response,body) {
        //process external response.
        var respData = processBody(
        if (!error && response.statusCode == 200) {
            res.send(respData);
        } else {
            // send error.
            res.send(...);
        }
      }
    );
}