【问题标题】:Download files from server using Meteor.js使用 Meteor.js 从服务器下载文件
【发布时间】:2013-08-28 01:15:14
【问题描述】:

这是我目前的工作流程:

在按钮单击事件中,我将搜索结果导出到 .csv 文件,该文件保存到服务器。保存文件后,我想将其发送到浏览器下载。使用这个问题How to handle conditional file downloads in meteor.js,我创建了一个在保存文件的方法返回后调用的方法。这是那个方法:

exportFiles: function(file_to_export) {
    console.log("to export = "+file_to_export);
    Meteor.Router.add('/export', 'GET', function() {
        console.log('send '+file_to_export+' to browser');
        return [200,
        {
           'Content-type': 'text/plain',
           'Content-Disposition': "attachment; filename=" + this.request.query.file
        }, fs.readFileSync( save_path + this.request.query.file )];
    });
}

然而,我的问题是如何调用该路由?使用.Router.to('/export?file=filename.ext') 不起作用,并导致用户离开当前页面。我希望这对用户来说是无缝的,我不希望他们知道他们正在被重定向。在有人问之前,save_path 是在方法之外声明的,所以它确实存在。

【问题讨论】:

    标签: javascript meteor download url-routing


    【解决方案1】:

    我收到了!但是,它需要使用一些额外的软件包。首先,让我更清楚地描述一下工作流程:

    我们网站上的用户执行搜索。在随后的搜索结果页面上,存在一个按钮,允许用户将他/她的搜索结果导出到 .csv 文件。然后将文件导出到浏览器进行下载。

    我们担心的一个问题是,如果将文件写入服务器,请确保只有导出文件的用户才能查看文件。为了控制谁可以查看文件,我使用了一个陨石包 CollectionFS(mrt add collectionFS 或从github 克隆)。此包将文件缓冲区写入 mongo 集合。保存时提供“所有者”字段可让您控制访问。

    无论文件是如何创建的,无论是通过上传表单保存到服务器还是像我使用 json2csv 包那样即时生成,文件都必须作为缓冲区流式传输到 CollectionFS。

    var userId = Meteor.userId()
    var buffer = Buffer(csv.length);  //csv is a var holding the data for write
    var filename = "name_of_file.csv";
    for ( var i=0; i<csv.length; i++ ) {
      buffer[i] = csv.charCodeAt(i);
    }
    CollectionFS.storeBuffer(filename, buffer, {
        contentType: 'text/plain',
        owner: userId
    });
    

    所以此时,我已经获取了我的数据文件,并将其作为缓冲区流式传输到 mongo 集合中。因为我的数据存在于 var csv 的内存中,所以我通过循环遍历每个字符将其作为缓冲区流式传输。如果这是保存在物理磁盘上的文件,我会使用 fs.readFileSync(file) 并将返回的缓冲区发送到 CollectionFS.storeBuffer()。

    现在文件在 mongo 中保存为缓冲区并拥有所有者,我可以通过发布 CollectionFS 集合的方式来限制可以下载/更新/删除文件甚至知道文件存在的人。

    为了从 mongo 读取文件并将文件发送到浏览器进行下载,需要另一个 Javascript 库:FileSaver (github)。

    使用 CollectionFS 中的 retrieveBlob 方法,通过提供引用 mongo 集合中文件的 _id 将文件作为 blob 从 mongo 中拉出。 FileSaver 有一个方法 saveAs,它接受一个 blob,并以指定的文件名导出到浏览器以供下载。

    var file = // file object stored in meteor
    CollectionFS.retrieveBlob(file._id, function(fileItem) {
        if ( fileItem.blob ) saveAs(fileItem.blob, file.filename);
        else if ( fileItem.file ) saveAs(fileItem.file, file.filename);
    });
    

    我希望有人会觉得这很有用!

    【讨论】:

    • 它是否适用于外部服务文件的直接链接或仅适用于文本文件?
    • 假设您能够读取文件并将其作为缓冲区流式传输到 CollectionFS,外部服务上文件的链接应该可以正常工作。
    【解决方案2】:

    如果您的路由有效,当您的方法返回时,您可以打开一个包含文本文件链接的新窗口。

    您已经添加了内容处置标头,因此文件应始终要求保存。

    即使您只是重定向到该文件,因为它具有这些内容处置标头,它也会要求保存并且不会中断您的会话。

    【讨论】:

    • 感谢您的回复!是的,这似乎是它应该做的。我在第 2 行的 console.log() 被调用,所以我知道该方法正在输入。但是,在方法返回后,我尝试执行 Meteor.Router.to(/export?file=filename.ext') 并且它重定向到一个空页面并且没有出现下载对话框。关于我做错了什么的任何线索?
    • 也许您不需要方法块内的Meteor.Router.add?反正你只需要运行一次,因为你通过了file=xx。它可以在流星启动时运行,然后只重定向到没有method/call 的文件。如果需要,您可以检查它是否使用令牌或查询字符串中的某些内容进行了身份验证
    猜你喜欢
    • 1970-01-01
    • 2015-02-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-09-28
    相关资源
    最近更新 更多