Reputation: 20526
I have the following code in Node/Express that sends a file as a response then deletes the file using a timeout.
res.sendFile(req.params.id, { root: process.env.UPLOADPATH });
setTimeout(function () {
if (fs.existsSync(process.env.UPLOADPATH + req.params.id)) { // check to ensure file still exists on file system
fs.unlink(process.env.UPLOADPATH + req.params.id); // delete file from server file system after 60 seconds
}
}, 60000);
If I didn't use the setTimeout
it failed with an error. I'm assuming Express does the sendFile
async so it was deleting the file before it actually sent.
Is there a better way to do this tho? Is there a way to check for when the file has been sent so I can safely delete it? Maybe like a sendFile
callback or something?
Upvotes: 3
Views: 5272
Reputation: 20526
The main drawback to res.on('finish', ...)
is that it isn't called on the response being closed or on an error. Using on-finished will run the callback on closes, finishes, or errors. This is especially helpful in the case of deleting a file where you want to delete the file even on errors or situations like that.
Upvotes: 1
Reputation: 707328
Is there a better way to do this tho? Is there a way to check for when the file has been sent so I can safely delete it? Maybe like a sendFile callback or something?
Yes, you should just remove the file when the res.sendFile()
is actually done. You can use the completion callback on res.sendFile()
to know when it's done.
Also, it is an anti-pattern to use if (fs.existsSync(...))
and then delete the file because it can be subject to race conditions. If you want the file deleted, just delete it and handle any errors you might get:
let filename = path.join(process.env.UPLOADPATH, req.params.id);
res.sendFile(filename, function (err) {
if (err) {
next(err);
} else {
try {
fs.unlink(filename);
} catch(e) {
console.log("error removing ", filename);
}
}
});
I'm assuming Express does the sendFile async so it was deleting the file before it actually sent.
Yes, that is true.
You could also use the res.on('finish', ...)
event to know when the sending of the response is done.
let filename = path.join(process.env.UPLOADPATH, req.params.id);
res.sendFile(filename);
res.on('finish', function() {
try {
fs.unlink(filename);
} catch(e) {
console.log("error removing ", filename);
}
});
Upvotes: 7
Reputation: 4565
The method invokes the callback function fn(err) when the transfer is complete or when an error occurs. If the callback function is specified and an error occurs, the callback function must explicitly handle the response process either by ending the request-response cycle
res.sendFile(fileName, { root: process.env.UPLOADPATH }, function (err) {
if (err) {
next(err);
} else {
// File has been sent
console.log('Sent:', fileName);
if (fs.existsSync(process.env.UPLOADPATH + req.params.id)) {
// check to ensure file still exists on file system
fs.unlink(process.env.UPLOADPATH + req.params.id);
// delete file from server file system after 60 seconds
}
}
});
Upvotes: 1