Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Express.js Response Sent Callback

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?

like image 298
Charlie Fish Avatar asked Apr 12 '26 03:04

Charlie Fish


2 Answers

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); 
      }
  });
like image 91
jfriend00 Avatar answered Apr 13 '26 20:04

jfriend00


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
       }
    }
  });
like image 24
digit Avatar answered Apr 13 '26 19:04

digit



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!