最近有个项目会用到文件下载的功能,因为在文件上传的时候,有更改文件名称的情况,但这个文件名称的更改只是软关联,并不是真的把上传的文件名称给改变,所以如果在文件下载的时候不显示文件原本的名称而显示更改后的文件名称体验会更好。
网上查找了一通方案,发现最靠谱的莫过于让后端不返回 文件流
而是返回blob数据
,然后前端自行通过createObjectURL
来进行下载。
axios请求是这样配置的:
download({}, fileId) { // 文件下载请求
return new Promise((resolve, reject) => {
http({
method: 'get',
url: `/file/download/${fileId}`,
responseType: 'blob'
}).then(rs => {
if(rs.status === 200){
resolve(rs)
}else{
reject(rs)
}
})
})
}
下面是点击下载按钮时执行的函数:
download (fileId, fileName) {
this.$store.dispatch('download', fileId).then(rs => {
const { status, data } = rs
if (status === 200) {
if (window.navigator.msSaveOrOpenBlob) {
navigator.msSaveBlob(data, fileName)
} else {
const link = document.createElement('a')
const body = document.querySelector('body')
link.href = window.URL.createObjectURL(data)
link.download = fileName
link.style.display = 'none'
body.appendChild(link)
link.click()
body.removeChild(link)
window.URL.revokeObjectURL(link.href)
}
} else {
this.$message.fail('文件下载失败!')
}
})
}
看着一切都ok的样子,但实际执行却发现返回的data
不是blob
,假如用new blob([data])
方法转换成blob数据,下载倒是能下载了,但明显数据不对,无法正常打开。
blob
本身对大部分前端来讲是个比较陌生的东西,在各种折腾后几乎以为是后端只能返回文件流而没法返回blob
。
有时候不得不说是柳暗花明又一村,在快要放弃时,偶然发现网上有个同样存在此问题的说起了 mockjs
存在时会导致responseType
设置失效。
把main.js
引入的mockjs
一试,果真如此,下载正常,谷歌/IE/火狐下均未发现问题。