浏览器下载文件 使用a 标签, 此标签有一个download 属性(可以设置下载文件的别名和类别) ,href 如果是同源的会直接下载,否则就普通跳转;
<a href="/11.png" download="image.png">下载同源文件</a>
<a href="/axios.html" download="downloadName">下载同源文件</a>
<a href="www.baidu.com" download="">非同源文件</a>
如果后台返回的是一个二进制流 (后台返回content-type为application/octet-stream)
需要设置responseType:' arraybuffer' 或者 responseType:'blob ' (注意这个字段不是放在请求头的)
axios 就可以在请求拦截器设置
const service= axios.create({
baseURL: 'xxxx',
timeout: 1000
})
// 请求拦截
service.interceptors.request.use(async (config) => {
// 判断只有 下载设置responseType
if (config.url.indexOf('downLoad') > 0) {
config.responseType = 'blob'
}
}, err => {
return Promise.reject(err)
})
service.interceptors.response.use(async res => {
// 判断是不是blob 格式或者 arraybuffer (考虑返回异常的情况, 异常情况会返回一个json 格式数据, 不需要进行下载处理)两者处理异常转成json 方式不同
if(res.request.response === 'blob') {
if(res.headers['content-type'].includes('application/json')) {
// 在这里对返回的blob 或者 arraybuffer 数据进行处理 , 需要转为json 格式数据 ,两个格式
的转换方式不同 blob 使用fileReader 读取(异步), arraybuffer使用TextDecoder +
Uint8Array 转换(同步)
let json = await blobHandle (res)
return json
} else {
return res
}
}
}, err => {
})
// 处理异步转换 Blob
const blobHandle = function (res) {
// 异步需要进行处理下 返回一个promise 对象
return new Promise((resolve, reject) => {
let reader = new FileReader(); // 创建读取文件对象
reader.readAsText(res.data, 'utf-8'); // 设置读取的数据以及返回的数据类型为utf-8
reader.addEventListener("loadend", function () { //
let res = {
data: JSON.parse(this.result)
}; // 返回的数据
resolve(responseHandle(res))
});
})
}
// arraybuffer
const arraybufferHandle = function (res) {
// 异步需要进行处理下 返回一个promise 对象
return new Promise((resolve) => {
const enc = new TextDecoder("utf-8")
const unit8Data = new Uint8Array(res.data)
const json = Json.parse(enc.decode(unit8Data))
resolve(json)
})
}
const responseHandle = function (res) {
// 系统异常
if (res.data.respCode === '9999') {
const msg = '系统异常,请稍后再试!'
MessageBox.confirm(msg, '提醒', {
confirmButtonText: '确认',
cancelButtonText: '取消',
type: 'warning'
}).then(() => { }).catch(() => { })
return Promise.reject(new Error(res.data.respDesc || 'Error'))
// 返回拦截
} else if (res.data.respCode != '00') {
// 登录拦截
if (res.data.respCode === '3002') {
MessageBox.confirm('登录信息已失效,请重新进行登录!', '提示', {
confirmButtonText: '登出',
cancelButtonText: '取消',
showCancelButton: false,
type: 'warning'
}).then(() => {
router.push({
path: '/login'
})
}).catch(() => {
router.push({
path: '/login'
})
})
} else { // 统一其他数据异常
Message({
message: res.data.respDesc || 'Error',
type: 'error',
duration: 5000
})
}
return Promise.reject(new Error(res.data.respDesc || 'Error'))
} else {
return res.data;
}
}
后台返回的二进制流数据需要把blob或者arraybuffer 转成blob 设置type(下载类型)
// 下载文件,处理二进制流 content-disposition响应头指示回复的内容该以何种形式展示
export function downloadFile(fileName = 'excel', res) {
let arr = res.headers['content-disposition'] ? res.headers['content-disposition'].split(';') : []
let obj = changeStrToObj(arr)
if (!obj.filename) {
obj.filename = `${fileName}.xls`
}
// 文件名需要进行解码
obj.filename = window.decodeURI(obj.filename, "UTF-8");
// 获取资源标识符,利用资源标识符可以进行下载
const url = window.URL.createObjectURL(new Blob([res.data], { type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" }))
const link = document.createElement('a')
link.style.display = 'none'
link.href = url
link.setAttribute('download', `${obj.filename}`)
document.body.appendChild(link)
link.click()
document.body.removeChild(link)
URL.revokeObjectURL(url)
}
// 这个获取 res.headers['content-disposition'] 转成对象,获取filename , 真实的文件名
export function changeStrToObj(data) {
let newData = data.reduce((pre, item) => {
let newItem = item
let key = '',
value = ''
if (newItem.includes('=')) {
let splitArr = newItem.split('=')
key = splitArr[0]
value = splitArr[1]
} else {
key = newItem
value = newItem
}
pre[key.toLowerCase()] = value
return pre
}, {})
return newData
}
file: 文件信息, 一般上传input type="file",获取fileList 数组,包含file对象; file对象继承blob;
除了继承的属性size,type ; 还有文件名,文件修改时间等等
fileReader: 异步读取存储在用户计算机上的文件(或原始数据缓冲区)的内容,使用 File 或 Blob 对象指定要读取的文件或数据。readAsText/readAsDataUrl/readAsArrayBuffer 等等
readAsDataUrl可以获取base64字符串
let hh = new Blob(['sss', 'ffff'])
let reader = new FileReader(); // 创建读取文件对象
reader.addEventListener("loadend", function () { //
console.log(reader.result)
});
reader.readAsDataURL(hh, 'utf-8');
输出: data:application/octet-stream;base64,c3NzZmZmZg==
参考资料:
File - Web API 接口参考 | MDNhttps://developer.mozilla.org/zh-CN/docs/Web/API/FileBlob - Web API 接口参考 | MDNBlob 对象表示一个不可变、原始数据的类文件对象。它的数据可以按文本或二进制的格式进行读取,也可以转换成 ReadableStream 来用于数据操作。https://developer.mozilla.org/zh-CN/docs/Web/API/BlobArrayBuffer - JavaScript | MDNArrayBuffer 对象用来表示通用的、固定长度的原始二进制数据缓冲区。https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/ArrayBuffer
FormData - Web API 接口参考 | MDNhttps://developer.mozilla.org/zh-CN/docs/Web/API/FormData