NodeJS不触发浏览器中的保存文件对话框/ EmberJS不接收从服务器发送的文件

时间:2014-07-01 08:24:15

标签: javascript node.js pdf ember.js

我的情景
我有一个使用MEEN堆栈编写的应用程序(MySQL,ExpressJS,EmberJS,NodeJS)。在页面中,我有一个表单输入。我应该获取输入数据,将其发送到服务器,生成PDF并在EmberJS中显示。服务器在带有ExpressJS的NodeJS中,生成的文件在发送到前端之前写入磁盘。

我的问题

我无法在EmberJS中显示PDF文件。或者说,没有显示任何内容。在NodeJS和ExpressJS的后端,我将PDF文件的文件流发送回EmberJS。在Chrome中使用像Postman扩展名这样的REST客户端,会调用该对话框,我可以保存该文件。但是,在EmberJS中,没有出现对话框,但我可以在Chrome开发工具中使用console.log查看文件流的内容。
为什么会这样?

以下是我使用ExpressJS在NodeJS中发送文件的代码。

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);
  });
},


Ember.js中的代码,用于向服务器发送详细信息并获取数据。

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
    }
});

1 个答案:

答案 0 :(得分:1)

我认为问题在于这不是Ember.js问题,而是服务器问题,以及它是如何处理的。 jQuery无法将文件保存到磁盘,因为它存在安全风险。虽然扩展可以覆盖各种安全限制,但在Ember或任何其他JavaScript框架(使用jQuery)中,您不能强制将另存为对话框,因为这是由安全性强制执行的。 JavaScript无法写入您的本地文件格式(除了html 5本地存储,它在很多方面与cookie类似)。

因此,您无法以PDF格式保存。可能让它工作的唯一方法是允许浏览器本身捕获流并处理它:

你可以尝试这个plugin,但我不确定它是否有效,而且根本不推荐。

我建议你只使用浏览器中的纯链接,让服务器以适当的方式发回文件,而不是ajax调用。您可以使用表单提交它,也可以使用带有查询字符串参数的纯链接。

客户端:

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

<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>

服务器端:

在服务器中添加以下标题:

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

添加mime-type可能是个明智的想法:

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

完整代码:

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);

或者,如果您使用快递,则可以使用此helper

res.download(filePath)