前端二进制上传文件至腾讯云

1,778 阅读2分钟

任务描述: 一个涉及APP发布和升级的后台管理系统,需要前端上传apk、.APK、.ipa、.IPA的Android包或者IOS包,转换成二进制的形式上传至腾讯云,腾讯云返回200标识成功,成功后调用保存接口, 返回403表示失败。

思路:后台要求非formdata上传,所有不能设置

headers: {      'Content-Type': ' multipart/form-data'    },

只能用Blob或者FileReader。又要求bindary形式,只能用fileReader。

采坑点一:腾讯云采用PUT上传, 二进制的headers头部,要设置成

headers: {
          'Content-Type': 'application/octet-stream'          
}

采坑点二:用fileReader读取的文件,文件流保存在event.target.result里面,即要传给后台的数据

采坑点三:fileReader的事件和方法具体情况具体分析。一开始我用的是readAsDataURL(), 此时返回的是base64的URL,而非binary对象,后来改为readAsArrayBuffer()

https://developer.mozilla.org/zh-CN/docs/Web/API/FileReader

采坑点四:我们框架用的element,上传用的upload组件。upload返回的file对象跟原生的有点区别,具体对象内容放在了file.raw里面,即file.raw = 原生file[0],一开始直接传的element的file对象给FileReader, 方法会报错。

具体实现:

const reader = new FileReader()
reader.readAsArrayBuffer(this.uploadData.file.raw)
reader.onload = async(event) => {
    axios.put(data.uploadUrl, event.target.result, {// event.target.result为读取到的流 
       headers: {
        'Content-Type': 'application/octet-stream'         
     }        
    }).then(res => {
        // 成功之后的方法       
     }).finally(_ => {
         // 最终执行的方法  前面读取之前加了loading  所以这里做清除操作          
        loading.close()         
    })      
    }     
 reader.onerror = (event) => {
     // 读取失败  提示       
     return this.$message.error(this.$kiwi.get('appModel.tips4'))      
}

此时FileReader读取文件上传腾讯云的操作就OK了,后台会解析拿到的包,返回相应的数据。

其次附上常用到的下载操作方法,相对上传比较简单,注意一点就是封装方法的responseType要设置为‘blob’,表明返回服务器返回的数据类型

responseType: 'blob'

/** * 文件流下载 * 
@param {Object} res 接口返回信息 * 
@param {String} type 文件类型 * 
@param {String} filename 下载后文件名 
*/
export function downloadFile(res, type, filename) {  // 这里res是返回的blob对象  
const blob = new Blob([res], { type: type })  
let v_filename = ''  
if (!filename) {    
    const contentDisposition = res.headers['content-disposition'] // 从response的headers中获取filename, 后端response.setHeader("Content-Disposition", "attachment; filename=xxxx.xls") 设置的文件名;    
    if (contentDisposition) {      
        const patt = new RegExp('filename=([^;]+\\.[^\\.;]+);*')      
        const result = patt.exec(contentDisposition)      
        v_filename = result[1] // 下载后文件名    
    } else { // content-disposition如果没有获取到,暂定文件名为SF     
         v_filename = 'XX' // 下载后文件名   
     }  
    } else {    
        v_filename = filename 
     }  
// 判断是不是ie浏览器  
if (!!window.ActiveXObject || 'ActiveXObject' in window) {    
    window.navigator.msSaveOrOpenBlob(blob, v_filename)  
} else {    
    const downloadElement = document.createElement('a')    
    const href = window.URL.createObjectURL(blob) // 创建下载的链接    
    downloadElement.style.display = 'none'    
    downloadElement.href = href    
    downloadElement.download = v_filename // 下载后文件名    
    document.body.appendChild(downloadElement)    
    downloadElement.click() // 点击下载   
    document.body.removeChild(downloadElement) // 下载完成移除元素    
    window.URL.revokeObjectURL(href) // 释放掉blob对象  
}}