vue项目中需要实现下载文件,后端不是给到文件地址,而是返回二进制文件流。
相关知识:
后端响应给我们二进制流文件,我们需要拿到相关信息并创建一个a标签并实现click,然后给下载的文件起个名字。
给下载文件起名字有两种方式:(1)固定值+时间戳(一般都加上时间戳)
(2)后端将文件名放到response的headers中返回,我们取值当做文件名。我们此次需求为第二种,名称后端定。
后端放到响应头中的字段长什么样子呢?
大约如下:
(1)Access-Control-Expose-Headers:content-disposition
// 大意就是允许访问请求头中的content-disposition字段,window系统默认是允许获取的,但是macOS系统默认不允许,不允许获取我们就没办法动态获取文件名。所以后端需要设置允许访问才可以解决macOS下载时动态获取文件名的错误。可以如下设置:
response.setHeader("Access-Control-Expose-Headers", "content-disposition");
(2)charset:utf-8,如果文件名为中文,在macOS下载后文件名乱码,window默认utf-8所以没有乱码。需要后端单独设置一下即可解决macOS乱码问题。可以如下设置:
response.setHeader("charset", "utf-8");
(3)Content-Disposition:attachment; filename=%E6%B3%95%E9%99%A2%E6%89%A7%E8%A1%8C%E4%BA%BA%E6%95%B4%E5%90%882_liumin_20200316225515562.xml
这个就是后端追加到headers中的信息,比如文件名是什么,下载方式是什么。我们要获取的文件名就在这里。
附上后端代码片段
vue实现代码:
let token = getStore("token") ? JSON.parse(getStore("token")) : ""
let url = `${api.baseURL}/dataSource/downloadInitFile?fileType=${type}` //改为所需的url
axios({
url: url,
method: "get",
responseType: "blob", // 注明响应类型为blob
headers: {
token: token
}
}).then(r => {
var headerInfo= r.headers//响应信息中的headers信息
var disposition= headerInfo["content-disposition"] // 后端通常会将文件名放入到headers中的content-disposition
filename = decodeURI(disposition.split(";")[1].split("filename=")[1]);
let createUrl = window.URL.createObjectURL(r.data)
const a = document.createElement("a")
a.href = createUrl
a.download = filename
document.body.appendChild(a)
a.click()
a.remove()
})