AkiraZ's blog

愿键盘的余温传递到更遥远的将来

中文 / English
0%

js 下载文件

下载类型

目前业务上碰到有两种下载类型,一种是返回的是文件在服务器上的所处位置,另一种返回的是整个文件的编码后的数组。这两者下载方式略有区别,但是大同小异。

下载资源

静态资源

后台服务器有静态资源且是固定的文件名(GET方式下载文件)

1
window.location.href="http://www.域名/template.xlsx(文件名)"

写全了就是

1
2
3
4
5
6
7
8
function download(fileName, link) {
let a = document.createElement('a');
a.download = fileName;
a.href = link;
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
}

解释一下代码,看起来是临时创建了一个 <a/> 标签,之后给标签赋值一个 download 文件名,一个 href 表示连接地址。之后临时加到页面上,模拟一个点击事件,执行下载,完事之后销毁。

返回文件流

Base64 编码

简述一下 Base64 编码,因为 URL 只能传输字符,所以这种方式的编码能把所有字符编码成 可打印字符

基本原理是,每三个字符一组,共 3*8=24 bits,分成四份,每份的 6bits 按照以下码值表转码。余下的位置用 = 占位

码值表
码值 字符 码值 字符 码值 字符 码值 字符
0 A 16 Q 32 g 48 w
1 B 17 R 33 h 49 x
2 C 18 S 34 i 50 y
3 D 19 T 35 j 51 z
4 E 20 U 36 k 52 0
5 F 21 V 37 l 53 1
6 G 22 W 38 m 54 2
7 H 23 X 39 n 55 3
8 I 24 Y 40 o 56 4
9 J 25 Z 41 p 57 5
10 K 26 a 42 q 58 6
11 L 27 b 43 r 59 7
12 M 28 c 44 s 60 8
13 N 29 d 45 t 61 9
14 O 30 e 46 u 62 +
15 P 31 f 47 v 63 /
举例
1
2
3
4
5
6
7
        J         S         c          r         i         p          t
Ascii 74 83 99 114 105 112 116
bin 01001010 01010011 01100011 01110010 01101001 01110000 01110100
6bits 010010 100101 001101 100011 011100 100110 100101 110000 011101 00 0000
dec 18 37 13 35 28 38 37 48 29 0
base64 S l N j c m l w d A
result SlNjcmlwdA==

注:6bits 分组不够时用 0 补齐;转为base64后不是4的倍数用 = 补齐

最后,base64是一种编码方式,而不是一种压缩方式,由于它使用4个字符来表示3个字符,总体大小会比原来大。

下载

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
axios.post(url, {
params
}, {
responseType: 'blob'
})
.then(function(res) {
var blob = res.data;
// FileReader主要用于将文件内容读入内存
var reader = new FileReader();
reader.readAsDataURL(blob);
// onload当读取操作成功完成时回调
reader.onload = function(e) {
var a = document.createElement('a');
// 获取文件名fileName
var fileName = res.headers["content-disposition"].split("=");
fileName = fileName[fileName.length - 1];
fileName = fileName.replace(/"/g, "");
a.download = fileName;
a.href = e.target.result;
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
}
}
);

一种实现

上图是一种实现,区别是这里使用了 FileReader 来将一个 Uint8Array 包装成了一个可读取的文件(dataURL)

FileReader

顺便提一下 FileReader

对象方法

方法名 参数 描述
abort none 中断读取
readAsBinaryString file 将文件读取为二进制码
readAsDataURL file 将文件读取为 DataURL
readAsText file, [encoding] 将文件读取为文本

事件

事件 描述
onabort 中断时触发
onerror 出错时触发
onload 文件读取成功完成时触发
onloadend 读取完成触发,无论成功或失败
onloadstart 读取开始时触发
onprogress 读取中

所以上面的就是

  • 读取文件成一个url
  • 在读取完成以后触发下载流程