My task at hand was to read a jpeg file in NodeJs and send it as http-response to answer a server request. Seemed to be trivial. However, my first solution failed. The browser did receive some binary gibrish, that was about 30% larger than the original file.
My code was (simplified; res is of type SeverResponse):
...
var fs = require('fs');
var stream = fs.createReadStream(pathToJPEG, {encoding: 'binary'});
res.setHeader('Content-Type', "image/jpeg");
stream.pipe(res);
...
As it turned out, what arrived at the browser was the UTF-8 encoded version of my source data. I also was able to exlude the response object to be the culprit. When I gave it an alternative stream (from Buffer, not file) it worked just fine.
Turns out the solution to my problem was to drop the option {encoding: 'binary'}. With that my browser received the right picture:
...
var fs = require('fs');
var stream = fs.createReadStream(pathToJPEG);
res.setHeader('Content-Type', "image/jpeg");
stream.pipe(res);
...
My question is: Why?
It seems intuitive that the first non-working version should be the correct one since it explicitly declares how to read the file.
The function fs. createReadStream() allows you to open up a readable stream in a very simple manner. All you have to do is pass the path of the file to start streaming in. It turns out that the response (as well as the request) objects are streams.
createReadStream() appears to have a synchronous interface. It does not return a promise or accept a callback to communicate back when it's done or to send back some results. So, it appears synchronous from the interface.
This is because the binary
encoding is not really binary
. createReadStream
uses the same encoding
parameters that accepted by Buffer. From the Node Buffer Docs:
'binary' - A way of encoding the buffer into a one-byte (i.e. latin-1) encoded string. The string 'latin-1' is not supported. Instead simply pass 'binary' to use 'latin-1' encoding.
Just set encoding to null
to get the raw stream or buffer, or don't specify anything at all, as you did in your second example.
Ixe is correct, changing encoding to null worked, but only after upgrading to a newer node/express package. Here is my code that correctly uploads a tar file:
fs.exists(filePath, function(exists){
if (exists) {
var stat = fs.statSync(filePath);
console.log('sending file, size %d', stat.size);
res.writeHead(200, {
"Content-Type": "application/x-tar",
"Content-Disposition": "attachment; filename=" + filePath,
"Content-Length": stat.size,
"Content-Transfer-Encoding": "binary"
});
fs.createReadStream(filePath, { encoding: null }).pipe(res); //must set encoding to null, as binary is not treated correctly
} else {
console.log('file not exist.');
res.writeHead(400, {"Content-Type": "text/plain"});
res.end("ERROR File does not exist");
}
});
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With