vue+axios文件上传/下载完美解决方案

需求分析: 因为axios在请求时定制了很多个性化需求,比如携带token,比如指明服务器域名等等,如果采用相对地址href的请求方式以及部分框架自带的文件上传方式,是无法满足需求的,我们的目的是采用相同的get和post完成文件下载和上传工作

下面直接分享解决方案

 //文件上传, 相对简单些,返回的都是json数据
submitUpload() {
    if(!this.checkUpload()) return false
        let fileFormData = new FormData();
        //this.file 更具不同ui框架获取的file对象,this.file.raw文件的二进制流
        fileFormData.append('file', this.file.raw);
        let requestConfig = {
         //重新设置请求头,考虑服务器处理时间可能过长,加大timeout
            headers: {
                'Content-Type': 'multipart/form-data',
                timeout: 20000,
            },
        }
        this.$axios.post(this.url, fileFormData, requestConfig).then(() => {
            this.$message({
                message: '文件上传成功',
                type: 'success',
                duration: 1500,
                onClose: () => {
                    //文件上传已经做成了组件.vue,向父类组件发送done消息,用于更新table等
                    this.$emit('done')
                }
            })
        })
},

//文件下载
//重点:一切正常,返回的是blob数据,创建一个a标签下载文件
//难点:如果服务器报,返回的可是一个json数据,特殊处理提取出来
download(){
    this.$axios.get(this.url, {
        responseType: 'blob', // important
        timeout: 20000,
    }).then((response) => {
        //返回的是一个错误
        if(response.headers['content-type']==='application/json'){
            //提取错误的json消息并转换(此时json消息依旧在response.data中,这是一个blob数据)
            let reader = new FileReader();
            reader.onload = e => this.$message.error(JSON.parse(e.target.result).msg);
            reader.readAsText(response.data);
            return false;
        }
        //接收的是文件,fileName是一个property,设置了默认值(比如"文件模版.xls")
        let fileName = this.fileName;
        //服务器返回的请求头中包含了文件名信息,提取出来
        //可能出现的BUG:如果在响应头中能看到"content-disposition",axios拿到的response却没有,
        //这不怪axios,你需要去服务器设置一个叫Access-Control-Expose-Headers的东西
        //让它包含"content-disposition"
        if(response.headers["content-disposition"]){
            const patt = new RegExp("filename=([^;]+\\.[^\\.;]+);*");
            const result = patt.exec(response.headers["content-disposition"]);
            if(result.length>1){
                //中文解码
                fileName = decodeURI(result[1]);
            }
        }
        //制作a标签并点击下载
        const url = window.URL.createObjectURL(new Blob([response.data],
            { type: 'application/octet-stream' }));
        const link = document.createElement('a');
        link.href = url;
        link.setAttribute('download', fileName);
        document.body.appendChild(link);
        link.click();
    });

总结: 文件上传在于获得文件二进制流并制作成FormData进行post请求,同时header需设置Content-Type='multipart/form-data'。
而文件下载则更复杂些,需从response.data中获得blob(文件二进制流)创建本地的下载标签a,最后点击下载,同时还需注意如果发生错误,服务器返回的是json数据,该数据依旧存在于response.data并以blob形式存在,需特殊处理提取出来并解析。
以上,依照不重复造轮子原则,可以把这两类分别做成两个组件,合理利用<slot>标签和property属性做到代码写一次,到处可复用原则。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容