Download a file from NodeJS Server using Express

Javascriptnode.jsFileExpressDownload

Javascript Problem Overview


How can I download a file that is in my server to my machine accessing a page in a nodeJS server?

I'm using the ExpressJS and I've been trying this:

app.get('/download', function(req, res){

  var file = fs.readFileSync(__dirname + '/upload-folder/dramaticpenguin.MOV', 'binary');

  res.setHeader('Content-Length', file.length);
  res.write(file, 'binary');
  res.end();
});

But I can't get the file name and the file type ( or extension ). Can anyone help me with that?

Javascript Solutions


Solution 1 - Javascript

Update

Express has a helper for this to make life easier.

app.get('/download', function(req, res){
  const file = `${__dirname}/upload-folder/dramaticpenguin.MOV`;
  res.download(file); // Set disposition and send it.
});
Old Answer

As far as your browser is concerned, the file's name is just 'download', so you need to give it more info by using another HTTP header.

res.setHeader('Content-disposition', 'attachment; filename=dramaticpenguin.MOV');

You may also want to send a mime-type such as this:

res.setHeader('Content-type', 'video/quicktime');

If you want something more in-depth, here ya go.

var path = require('path');
var mime = require('mime');
var fs = require('fs');

app.get('/download', function(req, res){

  var file = __dirname + '/upload-folder/dramaticpenguin.MOV';

  var filename = path.basename(file);
  var mimetype = mime.lookup(file);

  res.setHeader('Content-disposition', 'attachment; filename=' + filename);
  res.setHeader('Content-type', mimetype);

  var filestream = fs.createReadStream(file);
  filestream.pipe(res);
});

You can set the header value to whatever you like. In this case, I am using a mime-type library - node-mime, to check what the mime-type of the file is.

Another important thing to note here is that I have changed your code to use a readStream. This is a much better way to do things because using any method with 'Sync' in the name is frowned upon because node is meant to be asynchronous.

Solution 2 - Javascript

Use res.download()

It transfers the file at path as an “attachment”. For instance:

var express = require('express');
var router = express.Router();

// ...

router.get('/:id/download', function (req, res, next) {
    var filePath = "/my/file/path/..."; // Or format the path using the `id` rest param
    var fileName = "report.pdf"; // The default name the browser will use

    res.download(filePath, fileName);    
});

Solution 3 - Javascript

For static files like pdfs, Word docs, etc. just use Express's static function in your config:

// Express config
var app = express().configure(function () {
    this.use('/public', express.static('public')); // <-- This right here
});

And then just put all your files inside that 'public' folder, for example:

/public/docs/my_word_doc.docx

And then a regular old link will allow the user to download it:

<a href="public/docs/my_word_doc.docx">My Word Doc</a>

Solution 4 - Javascript

Here's how I do it:

  1. create file
  2. send file to client
  3. remove file

Code:

let fs = require('fs');
let path = require('path');

let myController = (req, res) => {
  let filename = 'myFile.ext';
  let absPath = path.join(__dirname, '/my_files/', filename);
  let relPath = path.join('./my_files', filename); // path relative to server root

  fs.writeFile(relPath, 'File content', (err) => {
    if (err) {
      console.log(err);
    }
    res.download(absPath, (err) => {
      if (err) {
        console.log(err);
      }
      fs.unlink(relPath, (err) => {
        if (err) {
          console.log(err);
        }
        console.log('FILE [' + filename + '] REMOVED!');
      });
    });
  });
};

Solution 5 - Javascript

In Express 4.x, there is an attachment() method to Response:

res.attachment();
// Content-Disposition: attachment

res.attachment('path/to/logo.png');
// Content-Disposition: attachment; filename="logo.png"
// Content-Type: image/png

Solution 6 - Javascript

'use strict';

var express = require('express');
var fs = require('fs');
var compress = require('compression');
var bodyParser = require('body-parser');

var app = express();
app.set('port', 9999);
app.use(bodyParser.json({ limit: '1mb' }));
app.use(compress());

app.use(function (req, res, next) {
    req.setTimeout(3600000)
    res.header('Access-Control-Allow-Origin', '*');
    res.header('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept,' + Object.keys(req.headers).join());
    
	if (req.method === 'OPTIONS') {
		res.write(':)');
		res.end();
	} else next();
});

function readApp(req,res) {
  var file = req.originalUrl == "/read-android" ? "Android.apk" : "Ios.ipa",
      filePath = "/home/sony/Documents/docs/";
  fs.exists(filePath, function(exists){
      if (exists) {     
        res.writeHead(200, {
          "Content-Type": "application/octet-stream",
          "Content-Disposition" : "attachment; filename=" + file});
        fs.createReadStream(filePath + file).pipe(res);
      } else {
        res.writeHead(400, {"Content-Type": "text/plain"});
        res.end("ERROR File does NOT Exists.ipa");
      }
    });  
}

app.get('/read-android', function(req, res) {
    var u = {"originalUrl":req.originalUrl};
    readApp(u,res) 
});

app.get('/read-ios', function(req, res) {
    var u = {"originalUrl":req.originalUrl};
    readApp(u,res) 
});

var server = app.listen(app.get('port'), function() {
	console.log('Express server listening on port ' + server.address().port);
});

Solution 7 - Javascript

There are several ways to do it This is the better way

res.download('/report-12345.pdf')

or in your case this might be

app.get('/download', function(req, res){
  const file = `${__dirname}/upload-folder/dramaticpenguin.MOV`;
  res.download(file); // Set disposition and send it.
});

Know More

Solution 8 - Javascript

Let's say you have created a form for files to be uploaded by the User.

<form action="/upload" method="POST"  enctype="multipart/form-data">
<input type="file" name="file"/>
<input type="submit" value="upload"/>
</form>

enctype="multipart/form-data" is just a data encoding protocol which is important, if you want to upload files

Now on the server-side, we can implement the following code to get the uploaded file

app.post('/upload', async (req, res) => {
let file = req.files.file
//dir is director where you want to move your file
file.mv(dir, (error) => {
    if (error) {
        res.end("file could not be uploaded")
     }
   })
 })

that's it the uploaded file will be moved to the desired path.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionThiago Miranda de OliveiraView Question on Stackoverflow
Solution 1 - JavascriptloganfsmythView Answer on Stackoverflow
Solution 2 - JavascriptJossef Harush KadouriView Answer on Stackoverflow
Solution 3 - JavascriptjordanbView Answer on Stackoverflow
Solution 4 - JavascriptVedranView Answer on Stackoverflow
Solution 5 - JavascriptBenoit BlanchonView Answer on Stackoverflow
Solution 6 - JavascriptKARTHIKEYAN.AView Answer on Stackoverflow
Solution 7 - JavascriptMD SHAYONView Answer on Stackoverflow
Solution 8 - JavascriptDigvijay YamagekarView Answer on Stackoverflow