前言
一图览全文,可以先看看大纲适不适合自己,如果你喜欢则继续往下阅读。
这一节呢,主要介绍一些前置知识,对一些基础知识的介绍,如果你觉得你是这个。⬇️⬇️⬇️,你可以跳过前言。
前端的文件下载主要是通过 `` ,再加上 download
属性,有了它们让我们的下载变得简单。
download
此属性指示浏览器下载 URL 而不是导航到它,因此将提示用户将其保存为本地文件。如果属性有一个值,那么此值将在下载保存过程中作为预填充的文件名(如果用户需要,仍然可以更改文件名)。此属性对允许的值没有限制,但是 /
和 \
会被转换为下划线。大多数文件系统限制了文件名中的标点符号,故此,浏览器将相应地调整建议的文件名。( 摘自 https://developer.mozilla.org/zh-CN/docs/Web/HTML/Element/a)
注意:
因此下载 url 主要有三种方式。(本文大部分以 blob 的方式进行演示)
兼容性
可以看到它的兼容性也非常的可观(https://www.caniuse.com/#search=download)
为了避免很多代码的重复性,因为我抽离出了几个公共函数。(该部分可跳过,名字都比较可读,之后若是遇到不明白则可以在这里寻找)
export function downloadDirect(url) {
const aTag = document.createElement('a');
aTag.download = url.split('/').pop();
aTag.href = url;
aTag.click()
}
export function downloadByContent(content, filename, type) {
const aTag = document.createElement('a');
aTag.download = filename;
const blob = new Blob([content], {
type });
const blobUrl = URL.createObjectURL(blob);
aTag.href = blobUrl;
aTag.click();
URL.revokeObjectURL(blob);
}
export function downloadByDataURL(content, filename, type) {
const aTag = document.createElement('a');
aTag.download = filename;
const dataUrl = `data:${
type};base64,${
window.btoa(unescape(encodeURIComponent(content)))}`;
aTag.href = dataUrl;
aTag.click();
}
export function downloadByBlob(blob, filename) {
const aTag = document.createElement('a');
aTag.download = filename;
const blobUrl = URL.createObjectURL(blob);
aTag.href = blobUrl;
aTag.click();
URL.revokeObjectURL(blob);
}
export function base64ToBlob(base64, type) {
const byteCharacters = atob(base64);
const byteNumbers = new Array(byteCharacters.length);
for (let i = 0; i < byteCharacters.length; i++) {
byteNumbers[i] = byteCharacters.charCodeAt(i);
}
const buffer = Uint8Array.from(byteNumbers);
const blob = new Blob([buffer], {
type });
return blob;
}
🚅🚅🚅🚅🚅🚅🚅🚅🚅🚅🚅🚅🚅🚅🚅🚅🚅🚅🚅🚅🚅🚅🚅🚅🚅🚅🚅🚅🚅
(手动给不看以上内容的大佬画分割线)
🇨🇳
所有示例Github地址:
https://github.com/hua1995116/node-demo/tree/master/file-download
在线Demo: https://qiufeng.blue/demo/file-download/index.html
后端
本文后端所有示例均以 koa / 原生 js 实现。
后端返回文件流
这种情况非常简单,我们只需要直接将后端返回的文件流以新的窗口打开,即可直接下载了。
// 前端代码
<button id="oBtnDownload">点击下载</button>
<script>
oBtnDownload.onclick = function(){
window.open('http://localhost:8888/api/download?filename=1597375650384.jpg', '_blank')
}
</script>
// 后端代码
router.get('/api/download', async (ctx) => {
const {
filename } = ctx.query;
const fStats = fs.statSync(path.join(__dirname, './static/', filename));
ctx.set({
'Content-Type': 'application/octet-stream',
'Content-Disposition': `attachment; filename=${
filename}`,
'Content-Length': fStats.size