我已经在SO中通过了一些建议的解决方案,但没有成功。这就是问题。当使用从API端点检索的数据生成blob时,我想强制浏览器下载blob。到目前为止,我已经尝试了三种解决方案,但它们都没有用。代码如下。请注意,我在代码中添加了一些注释以进一步解释。
const FILE_NAME_REGEX = /filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/;
export function Download(url) {
return APICall.get(url).then(response => {
const disposition = response.request.getResponseHeader('Content-Disposition');
//^This line gives the 'Refused to get unsafe header "Content-Disposition"' error, so next few lines won't execute and part with generating anchor is not used, but the part of code under the 'else' branch.
if (disposition && disposition.indexOf('attachment') !== -1) {
const matches = FILE_NAME_REGEX.exec(disposition);
if (matches != null && matches[1]) {
filename = matches[1].replace(/['"]/g, '');
}
}
const type = response.request.getResponseHeader('Content-Type');
const blob = new Blob([response.data], { type });
if (typeof window.navigator.msSaveBlob !== 'undefined') {
window.navigator.msSaveBlob(blob, filename);
} else {
const URL = window.URL || window.webkitURL;
const downloadUrl = URL.createObjectURL(blob);
if (filename) {
const a = document.createElement('a');
if (typeof a.download === 'undefined') {
window.location = downloadUrl;
} else {
a.href = downloadUrl;
a.download = filename;
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
}
} else {
// 1. soultion
window.location = downloadUrl;
}
setTimeout(() => {
URL.revokeObjectURL(downloadUrl);
}, 100);
}
});
}
// 2.解决方案
const ifrmDownloader = document.createElement('iframe');
ifrmDownloader.setAttribute('src', downloadUrl);
ifrmDownloader.style.width = '0px';
ifrmDownloader.style.height = '0px';
document.body.appendChild(ifrmDownloader);
// 3.解决方案
window.open(downloadUrl,_blank);
资源解释为Document但使用MIME类型image / png传输:“blob:https://example.com/e53bf47b-7f39-4758-b3dd-3cc2df5889ad”。
我觉得这里缺少一些东西,但是什么?
您的代码设置为仅在设置filename
变量时下载文件。
仅当您能够读取Content-Disposition标头时(即仅在同源时)才设置此变量。
所以简单的解决方法就是当你没有从Headers中获取它时为filename
设置一个虚拟值,这样,filename
总是被设置,你总是尝试下载它只是在新页面中打开它。
更聪明的解决方法是尝试从url
变量解析文件名,但不知道可能的URL的格式,很难为你制作一个。
const FILE_NAME_REGEX = /filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/;
export function Download(url) {
return APICall.get(url).then(response => {
const disposition = response.request.getResponseHeader('Content-Disposition');
if (disposition && disposition.indexOf('attachment') !== -1) {
const matches = FILE_NAME_REGEX.exec(disposition);
if (matches != null && matches[1]) {
filename = matches[1].replace(/['"]/g, '');
}
}
if (!filename) {
// getFileNameFromURL(url);
filename = 'dummy.png';
}
const type = response.request.getResponseHeader('Content-Type');
const blob = new Blob([response.data], {
type
});
if (typeof window.navigator.msSaveBlob !== 'undefined') {
window.navigator.msSaveBlob(blob, filename);
} else {
const URL = window.URL || window.webkitURL;
const downloadUrl = URL.createObjectURL(blob);
// if (filename) { // always truthy
const a = document.createElement('a');
if (typeof a.download === 'undefined') {
window.location = downloadUrl;
} else {
a.href = downloadUrl;
a.download = filename;
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
}
// }
/* else { // useless
window.location = downloadUrl;
}
*/
setTimeout(() => {
URL.revokeObjectURL(downloadUrl);
}, 100);
}
});
}
以下是我发现的问题。实际上有两个问题:
const chunks = extendedURl.split('/');
const pngExtension = '.png';
const baseName = chunks[chunks.length - 1].split('?')[0];
filename = `${baseName}${pngExtension}`;
一旦调用Get方法提供了'responseType:“arraybuffer”',文件开始显示正常,而不是'破坏'。
总而言之,当调用返回FileStreamResult的.net Core Web API端点时,为了能够在FE JavaScript中创建Blob,您应该将responseType显式设置为'arraybuffer',如下所示:
axios.get(extendedURl, { responseType: 'arraybuffer' }).then(response =>...