0

I can't seem to get my "download file" feature working using Expressjs.

//DOWNLOAD FILE
router.get('/snippets/download', function (req, res) {
  res.attachment("untitled.js");
  res.send("here is some javascript");
});

If I access this route in my browser the file downloads to my computer but not if I use an Angularjs request to the route.

Am I missing something?

tommyd456
  • 10,443
  • 26
  • 89
  • 163
  • what if you use get method? pass variable as a query if needed. FYI [Download a file from NodeJS Server](http://stackoverflow.com/questions/7288814/download-a-file-from-nodejs-server), [How to implement file download functionality using Node.js and express, so that the user is prompted to save the file?](http://stackoverflow.com/questions/14882310/how-to-implement-file-download-functionality-using-node-js-and-express-so-that) – Ian Wang Aug 26 '14 at 10:13
  • thanks will take a look - I tried a GET and if I just enter the path into the browser this works fine but if I send values from my app via GET then I get the same problem. – tommyd456 Aug 26 '14 at 10:15

2 Answers2

1

You can use res.download. Refer documentation here: http://expressjs.com/4x/api.html

Eg:

//DOWNLOAD FILE
router.post('/snippets/download', function (req, res) {
    res.download(req.body.filename, req.body.text);
});

See if this helps.

Chirag Jain
  • 2,378
  • 3
  • 21
  • 22
  • This doesn't appear to work - the contents of the req.body.text are outputted to the console window. – tommyd456 Aug 26 '14 at 10:55
  • first argument to download is the path to the file. Make sure req.body.filename is the correct path to the file. – Chirag Jain Aug 27 '14 at 04:42
  • 1
    The file does not exist - I want it to be made on the fly using the `req.body.text` - I don't want to store anything on my server. – tommyd456 Aug 27 '14 at 15:23
0

The res.download() method need a file's full path ( which could be different in windows and linux with different seperator ).

And the 2nd param of res.download(localName, downloadPromptName ) should be able to modify the filename that user see (different from the file in your server's directory), but it seems that does not work in my environment.

So I recommend you to use res.sendFile(fullNameInServer ,options) where you can modify the downloaded filename in options.

var root = getDownloadRoot(req);
var options =   {
    root: getDownloadRoot(req),
    headers: {
        "content": "text/html;charset=utf-8",
        "Content-Type": "application/octet-stream",
        "Expires":"0",
        "Cache-Control": "must-revalidate, post-check=0, pre-check=0",
        "content-disposition": "attachment;filename=" + urlencode(downloadFilename)
    }
};
res.sendFile( tempFileName ,options);   

urlencode should be required to encode filename then you can use filename other than english.

before call download file , you need to write the file physically in a temp folder, the getDownloadRoot() method give you the temp folder location in runtime which does not vary when you change the path to run the app.

here is the function getDownloadRoot()

function getDownloadRoot(req){
    var path = require('path');
    var sep = path.sep;
    var parentPath = path.dirname(req.settings.views);
    var ret = parentPath.concat(sep +  tempFileFolder);
    return ret;
}

For now I have no way other than using app.setting (that app is declared in app.js) to get the application folder during runtime. So I made a litte 'middleware' to transport the value with req object as following.

In app.js:

app.use(function(req, res, next) {
    req.settings = app.settings;
    next();
});

tempFileFolder is a folder that you can name it yourself.
sep is the folder seperator ( \ in windows and / in linux )

Also you need to watch the folder permission settings when running in linux.

This combination works perfectly in my environment (with angularjs)

jetwaves
  • 51
  • 3