web文件下载遇到的问题以及其他相关知识点

浏览器下载文件 使用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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值