站在巨人的肩膀上「让浏览器下载文件的一些手段」。
「让浏览器下载文件的一些手段」 对于如何实现文件下载已经做了很好的解说。总结起来有以下几种方法:
download 属性
常规的 <a>
标签通过 href 实现链接跳转,如果只想下载文件而不是跳转预览,最好的方式是在 <a>
标签中添加 download 属性,就能很简单地实现下载操作。
但是注意:此属性仅适用于同源 URL。
content-disposition
前后端配合完成文件下载的业务场景下,可以通过设置响应头的 Content-Disposition 实现。
Content-Disposition 决定了是以内联的形式(即网页或者页面的一部分),还是以附件的形式下载并保存到本地。
- inline:默认值,表示回复中的消息体会以页面的一部分或者整个页面的形式展示。
- attachment:消息体应该被下载到本地。大多数浏览器会呈现一个“保存为”的对话框,将 filename 的值预填为下载后的文件名。
跨域下载
结合 Blob 和 Fetch,获取跨域资源返回一个 Blob 对象并生成一个 Blob URL,配合 <a>
标签的 download 属性触发下载。
function download(href, filename = '') {
const a = document.createElement('a');
a.download = filename;
a.href = href;
document.body.appendChild(a);
a.click();
a.remove();
}
function downloadFile(url, filename = '') {
fetch(url, {
headers: new Headers({
Origin: location.origin,
}),
mode: 'cors',
})
.then(res => res.blob())
.then(blob => {
const blobUrl = window.URL.createObjectURL(blob);
download(blobUrl, filename);
window.URL.revokeObjectURL(blobUrl);
});
}
注意:跨域资源所在的服务器需要配置 Access-Control-Allow-Origin。
额外做一些补充
如何动态下载当前页面的内容,例如导出表格?
动态下载
同样我们可以基于 Blob URL 和 data URL 实现,并且已经有现成的 NPM 包 - js-file-download。源码如下(实现方式相同):
module.exports = function(data, filename, mime, bom) {
var blobData = typeof bom !== 'undefined' ? [bom, data] : [data];
var blob = new Blob(blobData, { type: mime || 'application/octet-stream' });
if (typeof window.navigator.msSaveBlob !== 'undefined') {
// IE workaround for "HTML7007: One or more blob URLs were
// revoked by closing the blob for which they were created.
// These URLs will no longer resolve as the data backing
// the URL has been freed."
window.navigator.msSaveBlob(blob, filename);
} else {
var blobURL =
window.URL && window.URL.createObjectURL
? window.URL.createObjectURL(blob)
: window.webkitURL.createObjectURL(blob);
var tempLink = document.createElement('a');
tempLink.style.display = 'none';
tempLink.href = blobURL;
tempLink.setAttribute('download', filename);
// Safari thinks _blank anchor are pop ups. We only want to set _blank
// target if the browser does not support the HTML5 download attribute.
// This allows you to download files in desktop safari if pop up blocking
// is enabled.
if (typeof tempLink.download === 'undefined') {
tempLink.setAttribute('target', '_blank');
}
document.body.appendChild(tempLink);
tempLink.click();
// Fixes "webkit blob resource error 1"
setTimeout(function() {
document.body.removeChild(tempLink);
window.URL.revokeObjectURL(blobURL);
}, 0);
}
};
application/octet-stream
js-file-download 的实现中将 Content-Type 设置为了 application/octet-stream
。Content-Type 对于文件下载有什么影响呢?
Content-Type 实体头部用于指示资源的 MIME 类型 media type 。
在响应中,Content-Type 标头告诉客户端实际返回的内容的内容类型。对于 text/html
/application/xml
这类浏览器可以直接预览的文件类型,当 content-disposition 没有特别的设置时,浏览器会默认进行预览。
而对于浏览器无法识别或不支持预览的类型,如 text/csv,会触发 另存为 行为(文件下载),交由对应的应用程序执行。
所以某些时候修改 Content-Type 也能实现文件下载。 😏😏😏