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



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

My problem:

我无法在EmberJS中显示PDF文件。或者更确切地说,什么都不显示。在使用NodeJS和ExpressJS的后端中,我将PDF文件的文件流发送回EmberJS。在Chrome中使用REST客户端,如Postman扩展,对话框被调用,我可以保存文件。然而,在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
    }
});

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

因此你不能保存为PDF。实现这个功能的唯一方法可能是允许浏览器自己捕获流并处理它:

你可以试试这个插件,但我不确定它是否有效,所以不推荐使用。

我建议您使用浏览器中的纯链接,并让服务器以适当的方式将文件发送回来,而不是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);

或者如果你使用express,你可以使用这个helper

res.download(filePath)

最新更新