简体   繁体   中英

How to download/stream a file from a express + mongoDB server, using the browser download manager

So my title probably doesn't make much sense so let me explain, I am using express with mongoose/MongoDB to upload/download files, before I could just go to the browser URL and serve up a get file request like that, but I wanted to add authentication, and since I need to send a JWT token through the header, I am unable to just go to the URL through the browser, let me show you what I have so far.

router.get('/file-service/download', auth, async (req, res) => {
  if (!req.user) {
    return res.status(401).send('Please authenticate');
  }

  try {
    const tempID = '5dc5f57a081263451cee80d4';

    const gfs = Grid(conn.db);

    gfs.findOne({ _id: tempID }, (err, file) => {
      //console.log("file", file);

      if (err) {
        return res.status(500).send(err);
      }

      res.set('Content-Type', file.contentType);
      res.set('Content-Disposition', 'attachment; filename="' + file.filename + '"');

      const readStream = gfs.createReadStream({
        _id: tempID
      });

      //console.log("grid", readStream);

      readStream.pipe(res);
    });
  } catch (e) {
    console.log(e);
    res.status(500).send(e);
  }
});

So I use to go to localhost:3000/file-service/download, and it would just start the download in chrome, with the native download manager, and show progress, everything you'd expect when downloading a file, but now this is not possible so instead I perform an axios request instead like so.

const config = {
  responseType: 'arraybuffer',
  headers: { Authorization: 'Bearer ' + 'jwtsecret' }
};

console.log('fetching download');

axios
  .get('http://' + currentURL + '/file-service/download', config)
  .then(response => {
    let blob = new Blob([response.data], { type: 'binary/octet-stream' });
    let link = document.createElement('a');
    link.href = window.URL.createObjectURL(blob);
    link.download = 'zip_test.zip';
    link.click();
  })
  .catch(err => {
    console.log(err);
  });

And this works, BUT, it has to first load the whole file into memory, for example, I was testing this with a 500mb file, after I do the axios request, it takes like 15+ seconds for it to fetch all the data, then it prompts to use with the download and finishes pretty much instantly. But if I remove the auth, and do it just through the browser via URL, the download starts instantly and shows progress in the chrome download like it normally would. Is there any way to achieve this same kind of download/streaming functionality with axios ? Or is there some way to send the token without axios so I can avoid it altogether and just do it the normal way?

You can pass the token as a query instead of a middleware ie http://localhost:3000/file-service/download?token=kjhdsjkf.sakhdh.asdkd and validate the token right before the user proceeds to download

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM