后端返回二进制文件流下载
首先文件流在浏览器展示乱码, 所以我们需要在请求中添加responseType: "blob", 告诉浏览器回调类型让其解析blob,以便我们创建Blob实例并解析
通常情况下在上传文件时我们的file中会告诉后端文件类型(每种文件类型对应一种MIME类型), 所以我们下载时可以直接让后端返回文件流的类型
// 下载文件的函数
async function handleDownload() {
// 调用下载文件的API,返回文件二进制内容
const res = await requestDownloadFile({ path: path.value })
downloadFile(res)
}
// 文件流解析并下载
function downloadFile(res) {
const blob = new Blob([res], { type: res.type })
// 创建一个a标签,将Blob对象作为URL,设置下载属性和文件名
const link = document.createElement('a')
link.href = window.URL.createObjectURL(blob)
link.download = new Date().getTime()
// 添加a标签到body中,模拟点击下载链接,完成下载后移除a标签
document.body.appendChild(link)
link.click()
document.body.removeChild(link)
}
由于种种原因后端没权限修改主系统上传下载代码(后端上传时加个字段接下的事)( -_- ), 因此出此下策:通过对应文件类型匹配MIME类型,通过Blob告诉浏览器我们下载文件的类型
// 定义一个MIME类型字典
const dict = {
png: 'image/png',
jpg: 'image/jpeg',
jpeg: ' image/jpeg',
bmp: 'image/bmp',
doc: 'application/msword',
docx: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
xlsx: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
xls: 'application/vnd.ms-excel',
pdf: 'application/pdf',
zip: 'application/zip',
rar: 'application/x-rar-compressed',
}
/**
* 正则截取文件后缀名
* @param {String} fileName 文件名称
* @returns 文件类型
* @example fileExtReg('logo.png')
*/
function fileExtReg(fileName) {
return fileName.match(/\.([^.]+)$/)[1];
}
// 下载文件的函数
async function handleDownload() {
// 调用下载文件的API,返回文件二进制内容
const res = await requestDownloadFile({ path: path.value })
downloadFile(res)
}
// 文件流解析并下载
function downloadFile(res) {
// 将文件内容转成Blob对象,并设置MIME类型
const blob = new Blob([res], { type: dict[fileExtReg(name.value)] })
// 创建一个a标签,将Blob对象作为URL,设置下载属性和文件名
const link = document.createElement('a')
link.href = window.URL.createObjectURL(blob)
link.download = new Date().getTime()
// 添加a标签到body中,模拟点击下载链接,完成下载后移除a标签
document.body.appendChild(link)
link.click()
document.body.removeChild(link)
}
非文件流下载方法(后端直接给你文件在服务器中的地址)
/**
* *下载:需要注意的是,如果要确保文件下载时的兼容性和安全性,还需要在服务器端设置相关的响应头信息,例如设置 Content-Disposition 为 attachment。
* @param {String} url 地址
*/
function handleDownload(url) {
window.open(xxxxxxx, "_blank");
}
/**
* *下载:通过创建一个a标签,并将其链接地址指向要下载的文件,然后模拟用户点击该标签来触发文件下载操作。这种下载方式还可以通过download修改下载文件名称等
* @param {String} url 地址
*/
function downloadFile(url) {
var link = document.createElement("a");
link.href = url;
link.target = "_blank";
document.body.appendChild(link)
link.click()
document.body.removeChild(link)
}
文件流:文件名问题
一般来说,文件名字后端都在返回响应头里response.headers["content-disposition"],前后端可以约定文件名前用 ‘某’ 符号分隔。以便前端截取并进行解码处理,文件名称默认是URL编码后的字符串,如不是需要问一下后端格式,再作相应的解码
decodeURIComponent()该内置对象,接收编码后的部分,从而返回解码后的内容
// 假设str是response.headers['content-disposition']返回的文件名
let str = "filename=%E6%B5%8B%E8%AF%95.zip"
const fileTxt = response.headers['content-disposition'].split('=')[1].replace(/^"|"$/g, '')
console.log(fileTxt) // e6b58be8af95.txt
const fileName = fileTxt.split('.')[0] // 文件名
const fileType = fileTxt.split('.')[1] // 文件类型
const decodeFileName = decodeURIComponent(fileName)
// 此时已经解决文件名/文件类型的问题,将响应体返回
return {
data: {
fileType,
fileName: decodeFileName,
},
fileStream: response.data, // 文件流
}
// 后续没什么好说的,上方讲过: 文件流解析并下载
// 定义一个MIME类型字典
const dict = {
png: 'image/png',
jpg: 'image/jpeg',
jpeg: ' image/jpeg',
bmp: 'image/bmp',
doc: 'application/msword',
docx: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
xlsx: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
xls: 'application/vnd.ms-excel',
pdf: 'application/pdf',
zip: 'application/zip',
rar: 'application/x-rar-compressed',
}
function downloadFile(res) {
// 将文件内容转成Blob对象,并设置MIME类型
const blob = new Blob([res.fileStream], { type: dict[res.data.fileType] })
// 创建一个a标签,将Blob对象作为URL,设置下载属性和文件名
const link = document.createElement('a')
link.href = window.URL.createObjectURL(blob)
link.download = new Date().getTime()
// 添加a标签到body中,模拟点击下载链接,完成下载后移除a标签
document.body.appendChild(link)
link.click()
document.body.removeChild(link)
}