0%

前端下载文件的2种方式

  • 要求导出excel文件,前端触发,后端直接返回文件, 记录一下遇到的问题与方法。

使用axios + blob + a标签

  • 方法
    • 前端使用axios 拿到二进制文件流
    • 从headers里的 Content-Disposition 提取文件名
    • 创建一个a 标签 触发下载行为
  • 前端代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
let params = {"file": 'a.xlsx'}
axios.get(url,{params:params, responseType: "blob",})
.then((res) => {
const { data, headers } = res;

// 提取文件名
let fileName = headers["content-disposition"].replace(/\w+;filename=(.*)/,"$1");

fileName = decodeURI(fileName); // url解码,防止中文乱码

// 构建a标签
const blob = new Blob([data], { type: headers["content-type"] });
const a = document.createElement("a");
a.download = fileName;
a.href = window.URL.createObjectURL(blob);
a.click();
})
  • 问题
    • 网上基本都是这么写的,但是问题来了, 我从headers里拿不到content-disposition ,检索了一下,可以用getResponseHeader方法试试
1
2
3
console.log(res.request.getResponseHeader("Content-Disposition"));
//得到了一个报错
Refused to get unsafe header "Content-Disposition"
  • 知道了问题,就可以再次检索,原来受限于CORS保护,被屏蔽了,可以在服务端添加header解决
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 以Djnago 为例
from django.http import HttpResponse
import urllib.parse


# ...


with open(file_path, "rb") as f:
filename = urllib.parse.quote(filename) #中文需要url编码
response = HttpResponse(f.read())
response["Content-Type"] = "application/vnd.ms-excel" #文件类型
response["Content-Disposition"] =f"attachment;filename={filename}" #文件名

# 允许Content Disposition 暴露
response["Access-Control-Expose-Headers"] = "Content-Disposition"
return response
  • 正确添加Header后,axios 就可以正常工作了。

  • 总结:

    • 提出正确的问题,问题就解决了一半了
    • google + stackoverflow 是程序员的第一生产力。如果不是,就是提问的关键词不对\( ̄▽ ̄)/.

通过URL 直接下载

  • 使用 window.open(url) 触发浏览器的下载行为 (在新窗口打开链接)

参考

欢迎关注我的其它发布渠道