如何打开POST生成的CSV文件

时间:2016-08-22 11:42:58

标签: javascript html angularjs rest single-page-application

我正在尝试实现这些看似简单的要求但却无法找到方法:

  • 使用Angular JS的单页应用
  • REST(ish)后端
  • 通过POST请求公开的后端资源
  • 在请求正文中作为JSON传递的资源参数
  • 资源生成CSV文件
  • 当用户点击按钮时,在正文中生成具有正确JSON参数的请求,发送它,并允许用户将响应下载为文件(提示浏览器的“打开/另存为”对话框)

问题主要是,如何将JSON作为请求体传递?最常见的技术似乎是隐藏的HTML表单来触发下载,但HTML表单无法在正文中发送JSON数据。而且我找不到任何方法来使用XMLHttpRequest来触发下载对话框...

有什么想法吗?

我指定了Angular,但任何通用的JS解决方案也非常受欢迎!

1 个答案:

答案 0 :(得分:0)

我终于找到了一个满足我所有要求的解决方案,并且可以在IE11,FF和Chrome中运行(并且降低了Safari中的确定......)。

我们的想法是创建一个包含响应数据的Blob对象,然后强制浏览器将其作为文件打开。 IE(专有API)和Chrome / FF(使用链接元素)略有不同。

这是一个实现,作为一个小的Angular服务:

myApp.factory('Download', [function() {
    return {
        openAsFile : function(response){

            // parse content type header
            var contentTypeStr = response.headers('Content-Type');
            var tokens = contentTypeStr.split('/');
            var subtype = tokens[1].split(';')[0];
            var contentType = {
                type : tokens[0],
                subtype : subtype
            };

            // parse content disposition header, attempt to get file name
            var contentDispStr = response.headers('Content-Disposition');
            var proposedFileName = contentDispStr ? contentDispStr.split('"')[1] : 'data.'+contentType.subtype;

            // build blob containing response data
            var blob = new Blob([response.data], {type : contentTypeStr});

            if (typeof window.navigator.msSaveBlob !== 'undefined'){
                // IE : use proprietary API
                window.navigator.msSaveBlob(blob, proposedFileName);
            }else{
                var downloadUrl = URL.createObjectURL(blob);

                // build and open link - use HTML5 a[download] attribute to specify filename
                var a = document.createElement("a");

                // safari doesn't support this yet
                if (typeof a.download === 'undefined') {
                    window.open(downloadUrl);
                }

                var link = document.createElement('a');
                link.href = downloadUrl;
                link.download = proposedFileName;
                document.body.appendChild(link);
                link.click();
                document.body.removeChild(link);
            }
        }
    }
}]);

response参数需要一个$http响应对象。以下是使用POST请求的示例:

$http.post(url, {property : 'value'},  {responseType: 'blob'}).then(function(response){
    Download.openAsFile(response);
});

请注意responseType参数。没有这个,我的CSV数据被作为文本读取并以UTF-8(或16)存储在内存中,随后文件以相同的编码保存,导致Excel无法识别特殊字符,如éè等。因为我的CSVs旨在由Excel打开,服务器将它们编码为Windows 1252,我想保持这种方式。将responseType参数设置为blob即可实现此目的。

免责声明:它适用于任何文件类型。但我只用CSV文件测试过它!二进制文件的行为可能会有所不同!