reading file data into memory to serve it as a response is not really a good practice, for tiny files it might be ok but for bigger files, it certainly is not, instead you should be streaming your response data and that is what I will do now.
First of all How to read files into Memory
exports.getInvoice = (req, res, next) => { const orderId = req.params.orderId; Order.findById(orderId) .then(order => { if (!order) { return next(new Error('No order Found.')); } if (order.user.userId.toString() !== req.user._id.toString()) { return next(new Error('Unauthorized User.')); } const invoiceName = 'invoice-' + orderId + '.pdf'; const invoicePath = path.join('data', 'invoices', invoiceName); fs.readFile(invoicePath, (err, data) => { if (err) { return next(err); } res.setHeader('Content-Type', 'application/pdf') res.setHeader('Content-Disposition', 'inline; filename="' + invoiceName + '"') res.send(data); }) }) .catch(err => { return next(err); }) }; Now the streaming file comes in
const file = fs.createReadStream(invoicePath);
I will use that file read stream and call the pipe method to forward the data that is read in with that stream to my response because the response object is a writable stream actually
We can pipe our readable stram , the file stream into response and that means that the response will be streamed to the browser and will contain the data and the data will basically be downloaded by the browser step by step and for large files, this is a huge advantage because node never has to pre-load all the data into memory but just streams it to the client on the fly and the most it has to store is one chunk of data.
Again we are back to the buffer and streams, the chunks are what we work with, the buffers
basically gives us access to these chunks and here we don't wait for all the chunks to come together and concatenate them into one object, instead we forward them to the browser which then is also able to concatenate the incoming data pieces into the final file.
So now this streamed data created with that create read stream thing which is the recommended way of getting your
const invoiceName = 'invoice-' + orderId + '.pdf'; const invoicePath = path.join('data', 'invoices', invoiceName); const file = fs.createReadStream(invoicePath); res.setHeader('Content-Type', 'application/pdf') res.setHeader('Content-Disposition', 'inline; filename="' + invoiceName + '"'); file.pipe(res); }) .catch(err => { return next(err); }) };
Comments