【问题标题】:Download lengthy data as a CSV file将冗长的数据下载为 CSV 文件
【发布时间】:2013-09-06 16:28:35
【问题描述】:

我需要将视图中显示的表格的内容下载为 CSV 文件。我有代码可以正确格式化表格的内容,以便可以将其存储为 .csv 文件(例如,列分隔符是逗号,表格的每条记录都在新行中)。

所以,在我的控制器中,我有以下代码:

window.location.href = '/download?data=' + encodeURIComponent($scope.csvString);

我将 NodeJs 用于服务器部分。在这里,我有以下路由处理程序:

app.get('/download', function (req, res) {
    var data = req.query.data;

    res.attachment('data.csv');
    res.setHeader('Content-Type', 'text/csv');
    res.end(data);
});

这工作得很好。下载工作正常,下载文件中的数据为完美的 CSV 格式。没有问题。

当表中的记录太多时,即数据量很大时,就会出现问题。因此,查询参数非常大,我假设它超过了限制,因此,GET 请求返回 400(错误请求)错误 - 请注意,根据我的分析,请求永远不会到达服务器,而是我观察到使用 Chrome 开发者工具请求失败。在浏览器中,URL 就是www.my_domain.com/download?data=the_lengthy_data。就是这样。网页为空白/空,没有下载文件。

因此,我想知道如何下载冗长的数据?我遇到的所有示例都执行 GET 请求,因此我必须将冗长的数据作为查询参数传递。还有其他方法吗?

【问题讨论】:

  • 是不是前端生成的CSV数据,发送到服务器,再下载回客户端?
  • @SalehenRahman 是的,您的理解是正确的。

标签: node.js angularjs csv download


【解决方案1】:

不是您问题的真正答案,但从外观上看,您正试图“强制”下载客户端上生成的数据。然后在这种情况下,您可以创建一个数据 URI,其中直接包含数据。

你的 Angular JS 模板:

<a href="data:base64,{{btoa(csvString)}}" download>Download CSV</a>

你的控制器:

$scope.btoa = function (val) {
    return btoa(val);
};

因此,您的 DOM 应如下所示:

<!-- The link contains data to the CSV string "a,b,c" -->
<a href="data:text/csv;base64,YSxiLGM=" download>Download CSV</a>

点击链接下载 CSV 文件。

编辑

您还可以使用名为 FileSaver.js 的库强制下载字符串。

像往常一样,您将获得 CSV,但这次,您会将其转换为 BLOB。

var csvBlob = new Blob([$scope.csvString], { type: 'text/csv;charset=utf-8' });

然后,您可以调用 FileSaver.js 的 saveAs 函数。

saveAs(csvBlob, 'mydata.csv');

【讨论】:

  • 我不是 100% 熟悉 AngularJS。我想你会将href 的值设置为$scope 等于'data:text/csv;base64,' + btoa($scope.csvString),但我不能100% 确定。
  • 我遵循了你的方法。然而,我不得不做出一些改变。而不是btoa(),我使用了encodeURI()。除此之外,AngularJs 会将unsafe: 附加到结果引用中。所以,我必须按照这篇文章stackoverflow.com/a/15265968/2104976 中的说明进行修复,并且成功了。谢谢。
  • 我更新了我的答案。出于某种原因,如果不重新定义函数,btoa 函数将无法工作。
  • 太棒了,我很高兴它有帮助! :)
【解决方案2】:

You're right about the character limit in the URL. 通常,长数据通过正文传递,因为理论上没有字符限制。

但是,您应该避免尝试在 GET 请求中传递正文。 The XMLHttpRequest specs on the send method say - “如果请求方法是 GET 或 HEAD,则将数据设置为 null。”。

所以我建议您使用 POST 请求并在正文中传递您的参数。因此,您还需要使用 app.post('download', ...) 重写处理程序,然后为这些参数解析 request.body。

根据我的理解,您正在尝试做什么,POST 似乎是更合适的 HTTP 动词,因为您提供的数据块要由服务器处理和返回。

【讨论】:

  • 我尝试过发布。但是,没有下载发生。还有什么可做的吗?代码和以前一样,只是现在 GET 是 POST 并且数据在 POST 请求的主体中传递...
  • 你在使用正文解析器吗? app.use(express.bodyParser());然后你可以使用 req.body
  • bodyParser 将正文视为 json。你能发送以 JSON 编码的数据并使用 req.body.csv 之类的东西
  • 是的 - 我也尝试过这种方法,我在一个对象内发送数据,其中“内容”作为键,实际数据作为值......没有帮助......
【解决方案3】:

我们需要改变 nodejs 代码如下。 Nodejs代码

    function downloadableFile(req, res) {
        res.attachment(document.title);
        var bufferStream = new stream.PassThrough();
        // we read the file in buffer.
        bufferStream.end(new Buffer(document.buffer));
        return bufferStream.pipe(res);
    }

Angularjs 不理解二进制数据。所以在前端我们可以使用第三方工具,比如 FileSaver.js'

var csvBlob = new Blob([$scope.csvString], { type: 'text/csv;charset=utf-8' }); saveAs(csvBlob, 'mydata.csv');

或者我们可以像这样使用 angularjs 代码。 Angularjs 代码。

    downloadDocument = function (path,id,type) {

    $http.get(path).then(function (data) {
    if (data.status === 404) {
        mpToastService.showToastHeader('error', 'Error downloading document');
    } else {
        var blob = new Blob([data.data],{
        type: type + ";charset=utf-8;"
        });
        $("#" + id).attr("href", window.URL.createObjectURL(blob));
        document.getElementById(id).click();
    }
    });
    }    

    //In html file, we need to include these two lines.

    <a ng-click="downloadDocument(document.path,document.id,document.mimeType)" >document.title</a>    
    <a id="document.id"></a>

此角码将在前端下载二进制数据,然后在流行的浏览器中弹出没有任何数据限制的下载模式。但通常这不是好的做法,除非客户有特殊要求。

【讨论】:

    猜你喜欢
    • 2018-11-19
    • 2014-02-06
    • 1970-01-01
    • 2015-11-12
    • 2017-09-12
    • 2021-08-25
    • 2021-11-22
    • 1970-01-01
    • 2013-07-07
    相关资源
    最近更新 更多