node.jsmongodbreactjsgridfsgridfs-stream

Download files from GridFS Stream NodeJS Backend / React Front End


I've set up a GridFS stream that serves zip files, if I type in the API url in the browser the zip file downloads onto my computer, which is what I want to happen. However when I do a get request from the front end React app, I get back a data object and no download effect. I've been able to get the download working using window.location.href but i've tested this in production and it just sends me to that localhost URL (which doesn't exist in production). Just looking to get some insight on this, my goal is the user can click a download button and the zip file gets sent to the user and starts downloading. Thanks!!


Solution

  • I decided to answer my own question if anyone comes across the same issue. To download a file from a GridFS stream, include a responseType: 'blob' on your axios request. And then save the file using a client side file library like FileSaver.

    Also make sure to include the appropriate headers on your back end route.

    client.js

    onDownloadSampleClick = () => {
        axios({
          method: "GET",
          url: "/api/test/stream/90b7d1d5ed550882284dcf6f62774963.zip",
          responseType: "blob"
        })
          .then(response => {
            this.setState({ fileDownloading: true }, () => {
              FileSaver.saveAs(response.data, "sparta_sample_pack.zip");
            });
          })
          .then(() => {
            this.setState({ fileDownloading: false });
            console.log("Completed");
          });
      };
    

    gridfs route

    router.get("/api/test/stream/:filename", (req, res) => {
      res.set({
        "Accept-Ranges": "bytes",
        "Content-Disposition": `attachment; filename=${req.params.filename}`,
        "Content-Type": "application/zip"
      });
      gfs.files.findOne({ filename: req.params.filename }, (err, file) => {
        if (!file || file.length === 0) {
          return res.status(404).json({
            error: "That File Doesn't Exist"
          });
        }
        if (file.contentType === "application/zip") {
          // Read output to browser
          const readstream = gfs.createReadStream(file.filename);
          readstream.pipe(res);
        } else {
          res.status(404).json({
            error: "This is not an zip file"
          });
        }
      });
    });