在 Angular 中从服务器下载文本/csv 内容作为文件

IT技术 javascript node.js angularjs http http-headers
2021-03-02 23:53:51

我正在尝试csv从 node.js 服务器流式传输文件。服务器部分非常简单:

server.get('/orders' function(req, res) {
  res.setHeader('content-type', 'text/csv');
  res.setHeader('content-disposition', 'attachment; filename='orders.csv');
  return orders.pipe(res); // assuming orders is a csv file readable stream (doesn't have to be a stream, can be a normal response)
}

在我的角度控制器中,我正在尝试做这样的事情

$scope.csv = function() {
    $http({method: 'GET', url: '/orders'});
};

ng-click在我的视图中单击按钮时会调用此函数

<button ng-click="csv()">.csv</button>

我查看了有关从 Angular 中的服务器下载文件的其他答案,但没有找到任何对我有用的答案。有没有一种通用的方法来做到这一点?看起来应该很简单。

5个回答

$http服务返回一个promise,它有两个回调方法,如下所示。

$http({method: 'GET', url: '/someUrl'}).
  success(function(data, status, headers, config) {
     var anchor = angular.element('<a/>');
     anchor.attr({
         href: 'data:attachment/csv;charset=utf-8,' + encodeURI(data),
         target: '_blank',
         download: 'filename.csv'
     })[0].click();

  }).
  error(function(data, status, headers, config) {
    // handle error
  });
虽然它以一种骇人听闻的方式工作:首先 chrome 的弹出窗口阻止程序阻止了点击,然后当我允许弹出窗口时,它在新窗口中打开下载。有没有办法让它更愉快?如果没有,我想这对我来说已经足够了:)
2021-04-28 23:53:51
要使其在 Mozilla Firefox 上运行,请将您的锚点附加到文档: angular.element(document.body).append(anchor);
2021-05-07 23:53:51
这并不能解决我的问题,因为它只是将文件内容打印到控制台。我需要以某种方式告诉它让浏览器处理下载...
2021-05-15 23:53:51
在 Mozilla Firefox 上不工作...在 Chrome 中工作正常。
2021-05-15 23:53:51
stackoverflow.com/a/35448277/3366706适用于 IE 11 和 chrome
2021-05-15 23:53:51

网络上有关此问题的大多数参考资料都指出,您无法通过“开箱即用”的 ajax 调用下载文件。我见过涉及的(hackish)解决方案iframes以及像@dcodesmith's 这样的解决方案,它们可以工作并且完全可行。

这是我发现的另一个解决方案,它适用于 Angular 并且非常简单。

视图中csv<a>以下方式标记包裹下载按钮

<a target="_self" ng-href="{{csv_link}}">
  <button>download csv</button>
</a>

(注意target="_self那里,在 ng-app 中禁用 Angular 的路由很重要,这里有更多关于它的信息

在您的控制器中,您可以定义csv_link以下方式:

$scope.csv_link = '/orders' + $window.location.search;

$window.location.search如果您想将额外的搜索查询传递给您的服务器,是可选的,并且是onlt)

现在,每次单击该按钮时,它都应该开始下载。

如果我们需要将一些大对象发布到服务器并获取生成的 word/pdf 文件,有什么方法可以做到这一点?
2021-04-28 23:53:51
此解决方案与具有由 angular 评估的带有 href 的简单 <a/> 标记没有什么不同。
2021-05-06 23:53:51
@ShivKumar 是的,响应 POST 请求,将 URL 返回到 csv。
2021-05-11 23:53:51
你能用完整的控制器和 UI 代码设置 JSFiddle 吗?
2021-05-12 23:53:51
var anchor = angular.element('<a/>');
anchor.css({display: 'none'}); // Make sure it's not visible
angular.element(document.body).append(anchor); // Attach to document

anchor.attr({
    href: 'data:attachment/csv;charset=utf-8,' + encodeURI(data),
    target: '_blank',
    download: 'filename.csv'
})[0].click();

anchor.remove(); // Clean it up afterwards

此代码适用于 Mozilla 和 chrome

谢谢你的回答。这个在 Chrome 和 Firefox 中确实有效。
2021-04-18 23:53:51
每个浏览器哪个版本?
2021-04-22 23:53:51
在 Firefox 和 chrome 中工作正常,但在 safari 中不起作用
2021-05-02 23:53:51
这是天才。该技术可用于从 angular 下载任意数据作为文件。
2021-05-13 23:53:51
什么是IE版本?
2021-05-15 23:53:51

这对 IE 11+、Firefox 和 Chrome 来说对我有用。在 safari 中,它下载一个文件,但未知且未设置文件名。

if (window.navigator.msSaveOrOpenBlob) {
    var blob = new Blob([csvDataString]);  //csv data string as an array.
    // IE hack; see http://msdn.microsoft.com/en-us/library/ie/hh779016.aspx
    window.navigator.msSaveBlob(blob, fileName);
} else {
    var anchor = angular.element('<a/>');
    anchor.css({display: 'none'}); // Make sure it's not visible
    angular.element(document.body).append(anchor); // Attach to document for FireFox

    anchor.attr({
        href: 'data:attachment/csv;charset=utf-8,' + encodeURI(csvDataString),
        target: '_blank',
        download: fileName
})[0].click();
anchor.remove();
}

使用角度 1.5.9

我通过将 window.location 设置为 csv 文件下载 url 让它像这样工作。经过测试,可与最新版本的 Chrome 和 IE11 配合使用。

   $scope.downloadStats = function downloadStats{
        var csvFileRoute = '/stats/download';
        $window.location = url;
    }

html

<a target="_self" ng-click="downloadStats()"><i class="fa fa-download"></i> CSV</a>

php中为响应设置以下标头:

$headers = [
    'content-type'              => 'text/csv',
    'Content-Disposition'       => 'attachment; filename="export.csv"',
    'Cache-control'             => 'private, must-revalidate, post-check=0, pre-check=0',
    'Content-transfer-encoding' => 'binary',
    'Expires' => '0',
    'Pragma' => 'public',
];