Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Node Express.js - Download file from memory - 'filename must be a string'

I'm trying to package data in memory into a text file and send it to the user, triggering a file download.

I have the following code:

app.get('/download', function(request, response){      fileType = request.query.fileType;     fileName = ( request.query.fileName + '.' + fileType ).toString();     fileData = request.query.fileData;      response.set('Content-disposition', 'attachment; filename=' + fileName );     response.set('Content-type', 'text/plain');      var fileContents = new Buffer(fileData, "base64");      response.status(200).download( fileContents );  }); 

It keeps throwing an error saying that Content-disposition's filename parameter must be a string. fileName is most certainly a string, so I'm not sure what is going on.

like image 402
Karric Avatar asked Aug 28 '17 15:08

Karric


People also ask

How do you make a node js file downloadable?

Downloading a file using node js can be done using inbuilt packages or with third party libraries. GET method is used on HTTPS to fetch the file which is to be downloaded. createWriteStream() is a method that is used to create a writable stream and receives only one argument, the location where the file is to be saved.

How do I download a file from node js server?

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.

How do I download from Express?

Installing Express Use the following command to install express: npm install express --save.


1 Answers

Update:

Thanks to @jfriend00's advice, it is better and more efficient to directly send Buffer to client as file, instead of saving it first in server disk.

To implement, stream.PassThrough() and pipe() can be used, here is an example:

var stream = require('stream'); //... app.get('/download', function(request, response){   //...   var fileContents = Buffer.from(fileData, "base64");      var readStream = new stream.PassThrough();   readStream.end(fileContents);    response.set('Content-disposition', 'attachment; filename=' + fileName);   response.set('Content-Type', 'text/plain');    readStream.pipe(response); }); 

According to Express document, res.download() API is:

res.download(path [, filename] [, fn])

Transfers the file at path as an “attachment”. Typically, browsers will prompt the user for download. By default, the Content-Disposition header “filename=” parameter is path (this typically appears in the browser dialog). Override this default with the filename parameter.

Please note the first parameter of res.download() is a "path", which indicates the path of file in server that would be downloaded. In your code, the first parameter is a Buffer, that's why Node.js complain that "filename parameter must be a string" -- By default, the Content-Disposition header “filename=” parameter is path.

To make your code work using res.download(), you need to save the fileData in server as a file, and then invoke res.download() with that file's path:

var fs = require('fs'); //... app.get('/download', function(request, response){   //...   var fileContents = Buffer.from(fileData, "base64");   var savedFilePath = '/temp/' + fileName; // in some convenient temporary file folder   fs.writeFile(savedFilePath, fileContents, function() {     response.status(200).download(savedFilePath, fileName);   }); }); 

Also, please note new Buffer(string[, encoding]) is deprecated now. It is better to use Buffer.from(string[, encoding]).

like image 197
shaochuancs Avatar answered Oct 13 '22 00:10

shaochuancs