如何打开 POST 生成的 CSV 文件
How to open a CSV file generated by POST
我正在尝试实现这些看似简单的要求但找不到方法:
- 使用 Angular JS 的单页应用程序
- REST(ish) 后端
- 后端资源通过 POST 请求公开
- 在请求正文中作为 JSON 传递的资源参数
- 资源生成 CSV 文件
- 当用户点击一个按钮时,在正文中生成一个带有正确 JSON 参数的请求,发送它,并允许用户将响应下载为一个文件(提示浏览器的 "open / save as"对话)
问题主要是,如何将JSON作为请求体传递?最常见的技术似乎是隐藏 HTML 表单来触发下载,但是 HTML 表单无法在正文中发送 JSON 数据。而且我找不到任何方法来使用 XMLHttpRequest 触发下载对话框...
有什么想法吗?
我指定了 Angular 但任何通用的 JS 解决方案也非常受欢迎!
我终于找到了一个可以满足我所有要求的解决方案,并且可以在 IE11、FF 和 Chrome 中运行(并且在 Safari 中降低了某种程度的 OK...)。
想法是创建一个包含响应数据的 Blob
对象,然后强制浏览器将其作为文件打开。对于 IE(专有 API)和 Chrome/FF(使用 link 元素)略有不同。
这是实现,作为一个小型 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);
}
}
}
}]);
响应参数需要一个 $http
响应对象。下面是一个使用 POST 请求的例子:
$http.post(url, {property : 'value'}, {responseType: 'blob'}).then(function(response){
Download.openAsFile(response);
});
注意 responseType
参数。如果没有这个,我的 CSV 数据将被读取为文本并以 UTF-8(或 16)格式存储在内存中,随后文件以相同的编码保存,导致 Excel 无法识别 éè 等特殊字符. 由于我的 CSV 旨在由 Excel 打开,服务器将它们编码为 Windows 1252,我想保持这种状态。将 responseType
参数设置为 blob
可实现此目的。
免责声明:它适用于任何文件类型。但我只用 CSV 文件测试过它!二进制文件的行为可能会有所不同!
我正在尝试实现这些看似简单的要求但找不到方法:
- 使用 Angular JS 的单页应用程序
- REST(ish) 后端
- 后端资源通过 POST 请求公开
- 在请求正文中作为 JSON 传递的资源参数
- 资源生成 CSV 文件
- 当用户点击一个按钮时,在正文中生成一个带有正确 JSON 参数的请求,发送它,并允许用户将响应下载为一个文件(提示浏览器的 "open / save as"对话)
问题主要是,如何将JSON作为请求体传递?最常见的技术似乎是隐藏 HTML 表单来触发下载,但是 HTML 表单无法在正文中发送 JSON 数据。而且我找不到任何方法来使用 XMLHttpRequest 触发下载对话框...
有什么想法吗?
我指定了 Angular 但任何通用的 JS 解决方案也非常受欢迎!
我终于找到了一个可以满足我所有要求的解决方案,并且可以在 IE11、FF 和 Chrome 中运行(并且在 Safari 中降低了某种程度的 OK...)。
想法是创建一个包含响应数据的 Blob
对象,然后强制浏览器将其作为文件打开。对于 IE(专有 API)和 Chrome/FF(使用 link 元素)略有不同。
这是实现,作为一个小型 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);
}
}
}
}]);
响应参数需要一个 $http
响应对象。下面是一个使用 POST 请求的例子:
$http.post(url, {property : 'value'}, {responseType: 'blob'}).then(function(response){
Download.openAsFile(response);
});
注意 responseType
参数。如果没有这个,我的 CSV 数据将被读取为文本并以 UTF-8(或 16)格式存储在内存中,随后文件以相同的编码保存,导致 Excel 无法识别 éè 等特殊字符. 由于我的 CSV 旨在由 Excel 打开,服务器将它们编码为 Windows 1252,我想保持这种状态。将 responseType
参数设置为 blob
可实现此目的。
免责声明:它适用于任何文件类型。但我只用 CSV 文件测试过它!二进制文件的行为可能会有所不同!