Home > Software design >  Getting "Failed - File incomplete" in Chrome when downloading file from MongoDB
Getting "Failed - File incomplete" in Chrome when downloading file from MongoDB

Time:05-08

My JavaScript application allows users to download a file. The page shows a clickable link to the file. The file is stored in MongoDB. When I click on the link to download the file, I'm getting "Failed - File incomplete" in Chrome. The file download should show up in my downloads file, but it doesn't. I don't know what is wrong and I hope someone here can shed some light on the problem.

This app is built using node/express/ejs/MongoDB

Here's the router code:

router.get('/:id/download', async (req, res) => {

    try {

        const bug = await Bug.findById(req.params.id)
        let buf = Buffer.from(bug.files)

        res.writeHead(200, {
            'Content-Disposition': `attachment; filename="${bug.fileName}"`,
            'Content-Type': bug.fileType,
            'Content-Length': buf.length,
        }).end()

        fs.writeFile(bug.fileName, buf, (err) => {
            if (err) {
                console.log(err);
            }
            else {
                console.log("File written successfully\n");
            }
        })

    } catch (err) {
        console.log("error downloading file", err)
    }

    res.end()
})

Here's the HTML:

<div >
    <div >
        <div ></div>
            <div >
                <h2>Bug Details</h2>
                <p>Title: <%= bug.title %></p>
                <p>Description: <%= bug.description %></p>
                <p>Category: <%= bug.category %></p>
                <p>Status: <%= bug.status %></p>
                <p>Priority: <%= bug.priority %></p>
                <p>Supporting Documents: </p>
                <a href="/<%= bug.id %>/download"><%= bug.fileName %></a>
                <div>
                <a href="/<%= bug.id %>/edit">Edit</a>
                <form  method="POST" action="/<%= bug.id %>?_method=DELETE">
                    <button type="submit">Delete</button>
                </form>
            </div>
            </div>
        <div ></div>
    </div>
</div>

In MongoDB the file is stored as part of a document:

files: {
        type: Buffer,
        required: false
    },

    fileName: {
        type: String,
        required: false
    },

    fileType: {
        type: String,
        required: false
    },

    fileSize: {
        type: Number,
        required: false
    }

When I test using a dummy .txt file, Chrome dev tools shows the response header as:

HTTP/1.1 200 OK X-Powered-By: Express Content-Disposition: attachment; filename="dummyfile.txt" Content-Type: text/plain Content-Length: 9 Date: Fri, 06 May 2022 20:19:01 GMT Connection: keep-alive Keep-Alive: timeout=5

One interesting side note: The file does download into my projects folder and everything is fine, but it doesn't download to my /downloads folder as it should.

CodePudding user response:

You should use res.download method which express provides, no need to set any headers.

Also, I'm using fs promises module for async await syntax

const fs = require("fs").promises;

router.get("/:id/download", async (req, res) => {
  try {
    const bug = await Bug.findById(req.params.id);
    let buf = Buffer.from(bug.files);
    await fs.writeFile(bug.fileName,buf);

    res.download(bug.fileName, err => {
      if (err) {
        throw err;
      } else {
        // If download is complete
        if (res.headersSent) {
          // if you want to delete the file which was created locally after download is complete
          fs.rm(bug.fileName);
        }
      }
    });
  } catch (err) {
    console.log("error downloading file", err);
  }
});

  • Related