文件下载是很多项目中的常见需求,实现方式通常是使用 a 标签实现:
<a href="url" download='filename'>下载</a>
在这种情况下,不支持跨域的链接,我们一般会用下面这种方式。
export function getUrlBlob(url: string): Promise<{ blobData: Blob; url: string }> {
var xhr = new XMLHttpRequest();
xhr.open('GET', url, true);
xhr.responseType = 'blob';
return new Promise((resolve, reject) => {
xhr.onerror = reject;
xhr.onload = function () {
const blob = this.response;
const blobData = new Blob([blob]);
resolve({
blobData,
url: window.URL.createObjectURL(blobData),
});
};
xhr.send();
});
}
export const exportDownload = async (url: string,filename:string) => {
let a = document.createElement('a');
a.href = (await getUrlBlob(url)).url;
a.download = filename;
a.click();
a.remove();
};
这中方法很常见,把资源下载到浏览器,在转成blob,生成一个临时的URL,这样就不会有跨域问题,但是这种情况会有个严重的问题,当文件比较大时就会很麻烦。
解决办法
- download参数
const urlObj = new URL(addHttpsToUrl(url));
urlObj.searchParams.set('download', filename);
a.href = urlObj.toString()
a.click();
window.URL.revokeObjectURL(a.href);
a.remove();
这种情况下载时,服务器可以根据download参数的值来设置下载的文件名为filename。
请注意,这个功能的可用性取决于服务器的实现。不是所有的服务器都支持这种方式来指定下载文件名。
2. response-content-type=application/octet-stream
const urlObj = new URL(addHttpsToUrl(url));
urlObj.searchParams.set('response-content-type=application', 'octet-stream');
a.href = urlObj.toString()
a.click();
window.URL.revokeObjectURL(a.href);
a.remove();
这种情况也可以下载,但是不支持自定义name