简体   繁体   中英

NodeJS not trigger save file dialog in browser / EmberJS not receive file sent from server

My scenario :
I have an app written using MEEN stack (MySQL, ExpressJS, EmberJS, NodeJS). In a page, I have a form input. I am supposed to get the input data, send it to server, generate a PDF and display in EmberJS. The server is in NodeJS with ExpressJS, and the generated file is written to disk before getting sent to front-end.

My problem :

I cannot display the PDF file in EmberJS. Or rather, nothing is displayed. In my back-end with NodeJS and ExpressJS, I send a filestream of the PDF file back to EmberJS. Using a REST Client like Postman extension in Chrome, the dialog is called, and I can save the file. However, in EmberJS, no dialog appears, but I can see the content of the filestream using console.log in Chrome Dev Tools.
Why is it like this?

Below is my code for sending the file in NodeJS with ExpressJS.

generatePDF: function(req, res){
  var details = req.body;
  // @param details
  // @return relative path to the file
  inventoryController.generatePDF(details, function(relPath){
    var filePath = path.resolve(relPath);

    // This is the first method
    // I explicitly specify the header for the Response Object
    // and pipe the ReadableStream to the Response Object

    // var name = path.basename(filePath);
    // var mimeType = mime.lookup(filePath);
    // res.setHeader('Content-disposition', 'attachment; filename=' + name);
    // res.setHeader('Content-type', mimeType);
    // var fileStream = fs.createReadStream(filePath);
    // fileStream.pipe(res);

    // This is the second method (currently being used)
    // using sendfile() of ExpressJS, the header is automatically set
    res.sendfile(filePath);
  });
},


The code in Ember.js for sending details to server and getting data back.

var doc = {
    // some attributes inside here
}; 
var url='/pdf';
var request = Ember.$.post(url, doc);

request.then(function(data){
    if(data.status === 'ERR'){
        // handling error 
    } else {
        console.log('Successfully generated PDF.');
        console.log(data); // I can see the filestream here
    }
});

I think the problem lies that this isn't an Ember.js issue but a server issue, and how it's handled. jQuery cannot save the file to disk, as it's a security risk. While extensions can override various security limitations, In Ember, or any other JavaScript framework (which uses jQuery) you cannot force a save as dialog as this is enforced by security. JavaScript cannot write to your local file format, (aside from html 5 local storage which is similar in many ways to cookies).

As such you cannot have a save as PDF. The only way to perhaps get that to work is allow the browser itself to capture the stream back and handle it:

You could try this plugin , but I'm not sure it works, and it's not recommended at all.

I'd recommend you just use a pure link from your browser and have the server send the file back in proper way, rather than an ajax call. You can either have a form submit it or a pure link with query string params.

Client Side:

<a href="/server/getFile?{"contentID"="123", "user" = "test@me"}>Get File</a>

or

<form action="/getFile" method="POST">
  <input type="hidden" id="user" name="user" value="test@me" />
  <input type="hidden" id="contentID" name="contentID" value="123" />
  <input type="submit" value="Get File />
</form>

Server Side:

Add in the server the following headers:

res.setHeader('Content-disposition', 'attachment; filename=<file name.ext>');

It might be a wise idea to also add a mime-type:

res.setHeader('Content-type', '<type>/<subtype>');

full code:

var filename = path.basename(filePath);
res.setHeader('Content-disposition', 'attachment; filename='+ filename);
res.setHeader('Content-type', 'application/pdf');
// it's better to use a stream than read all the file into memory.
var filestream = fs.createReadStream(filePath);
filestream.pipe(res);

Or if you're using express you could use this helper

res.download(filePath)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM