文件下载(URL,文档流)

2,540 阅读3分钟

根据后台返回的不同的内容进行文件下载的方法

1.后台返回url地址进行下载(.docx /.pptx /.txt /.png /.xls等等)

虽然说用window.open(url)也可以很方便进行文件的下载,但是下载图片和txt文件会变成打开另外一个页面,体验不太友好,所以封装了以下代码,方便各种文件的下载

course.vue

<template>
    <ul class="view-course-container clear">                    
        <li v-for="(course,courseIndex) in courseList.classArrangeFileList" :key="courseIndex">                        
            <div>                            
                <span :style="`background: url('static/img/${course.img}.png') center center no-repeat;`"></span>                            
                <div>                                
                    <p @click="downloadCourse(course.url,course.name)">{{course.name}}</p>                                
                    <var>{{course.createdTime}}  {{course.createUser}}上传</var>                            
                </div>                            
                <del @click="deleteFile(course.id)"></del>                        
            </div>                    
        </li>                
    </ul>
</template>
<script>
    export default {
        methods: {
            downloadCourse(url,name) {            
                this.$common.downloadFile(url, name)       
            }
        }
    }
</script>

common.js

// 下载资源    
downloadFile (url, fileName) {      
    let _this = this      
    let xhr = new XMLHttpRequest()      
    xhr.open('GET', url)      
    xhr.responseType = 'blob'      
    xhr.onload = function () {        
        // 请求完成        
        let blob = this.response        
        console.log(blob)        
        // 创建隐藏的可下载链接        
        let eleLink = document.createElement('a')        
        eleLink.download = fileName        
        eleLink.style.display = 'none'        
        // eleLink.href = url        
        eleLink.href = URL.createObjectURL(blob);        
        // 触发点击        
        document.body.appendChild(eleLink)        
        eleLink.click()        
        // 然后移除        
        document.body.removeChild(eleLink)      
    }      
    xhr.ontimeout = function(e) {         
        //下载超时请重试        
        console.log(e)        
        // _this.$message.error('下载超时请重试')      
    }      
    xhr.onerror = function(e) {        
        //下载出错        
        console.log(e)        
        // _this.$message.error('下载出错,请联系管理员')      
    }      
    // 发送ajax请求      
    xhr.send()    
},



2.后台返回的文档流前端下载Excel(get请求)

注意点:a标签下载不要传token

env.js文件

import Vue from 'vue'

let baseUrl = 'http://192.168.1.146:8002/ttfs-base-check'; // 测试环境
// 用户模块ip地址
let userUrl = 'http://192.168.1.146:8002/ttfs-user';  // 测试环境
// 分版本登录地址
Vue.prototype.$loginUrl = "http://192.168.1.146/manage";

export {    
    baseUrl,    
    userUrl
}

score.vue文件

<template>
    <a :href="excelUrl" class="download-excel">下载Excel</a>
</template>
<script>
    import { baseUrl, userUrl } from '@/config/env';
    export default {
        computed: {
            // excell模板下载地址            
            excelUrl () { 
                //所需的参数               
                let params = {                    
                    kSchoolId: this.kSchoolId,                    
                    kSchoolYearId: this.kSchoolYearId,                    
                    kSemesterId: this.newSemester.id,                    
                    kClassesGroupId: this.classId,                
                }                
                params.scoreClassesGroupId = this.tableFirstId;                
                if(this.orderCodeNum != -1) {                    
                    params.orderCode = this.orderCodeNum;                
                }                
                if(this.courseRankIndex != -1) {                    
                    params.kCourseId = this.scoreCourseId;                
                }
                //地址拼接
                let url = `${baseUrl}/api/score/classes/group/export`;                
                url += '?'                
                for(const item in params){     
                    //encodeURIComponent() 函数可把字符串作为 URI 组件进行编码               
                    url += encodeURIComponent(item) + '=' + encodeURIComponent(params[item]) + '&';                
                };                                
                return url            
            },
        }
    }
</script>


以上的方式虽然简单,但是下载不了的话报错不友好,会直接跳到一个300的页面,显示一段后台返回的报错信息,所以我又把它优化了一下,就是以下的样子

<template>
<div class="report" v.loading.fullscreen="loading" element-loading-text="拼命加载中...">
    <var class="score-analysis-download" @click="downloadExcel" v-if="classInfomation.classType!=undefined&&scoreId.id!==''">下载Excel</var>      
    <a :href="excelUrl" style="display:none" ref="loadA">下载Excel</a>
</div>
</template>
<script>
export default {
    data(){
        return{ 
            loading: true
        }
    },
    methods: {
      downloadExcel(e) {      
        this.loading = true;                
        let params = {              
            kSchoolId: this.kSchoolId,              
            kSchoolYearId: this.kSchoolYearId,              
            kSemesterId: this.newSemester.id,              
            scoreClassesGroupId: this.scoreId.id,              
            orderCode: 1          
        }          
        //行政班id          
        if(this.classInfomation.classType === 1 || this.classInfomation.classType === 6) {              
            params.kClassesGroupId = this.classInfomation.kClassesGroupId          
        }else{              
            params.kClassesGroupId = this.classInfomation.kClassId          
        }          
        this.$ajax.get('/api/score/classes/group/export', params).then(res => {            
            if(res.code == 300) {              
                this.loading = false;              
                this.excelUrl = 'javascript:;';              
                this.$message.error(res.msg);            
            }else{              
                let url = `${baseUrl}/api/score/classes/group/export`;              
                url += '?'              
                for(const item in params){                  
                    url += encodeURIComponent(item) + '=' + encodeURIComponent(params[item]) + '&';              
                };              
                this.excelUrl = url;              
                // e.target.href = url;              
                this.$nextTick(() => {                  
                    this.$refs.loadA.click();                  
                    this.loading = false;              
                })            
            }          
       });     
    }
}
</script>


this.$ajax为封装的axios代码,responseType默认为json格式

get(url, urlData, data = 0) {        
    this.isUserModel(url);        
    // 创建一个promise对象        
    // let data=JSON.stringify(datas);        
    // if(data==undefined){        
        this.promise = new Promise((resolve, reject) => {            
            if (data == 0) {                
                url += '?';                
                for (const item in urlData) {                    
                    // url += '/' + urlData[item];                    
                    // url += '?' +item+'=' +urlData[item];                    
                    url += item + '=' + urlData[item] + '&';                
                };            
            } else if (data == 1) {                
                for (const item in urlData) {                    
                    url += '/' + urlData[item];                    
                    // url += '?' +item+'=' +urlData[item];                
                };            
            }
            
        axios.get(url).then((res) => {                
            // debugger                
            if (this._isStatus(res.data)) {                    
                resolve(res.data);                    
                this.countlyMonitorResponse(url);                
            }            
        }).catch((err) => {                
            // console.log(err);                
            // Message.error(err);            
        })        
    })
        
    return this.promise;    
};


3.后台返回的文档流前端下载Excel(post请求)

当后台给的请求方法为post时,就不能直接用a标签添加地址来下载文件了,需要post请求接口,此时就需要用到另外一种方法,就是把后台返回的responseType


格式文件转化为arraybuffer二进制流文件,然后动态创建一个a标签来下载

<template>
    <div class="score">
        <span class="download-excel">下载Excel</span>
    </div>
</template>
<script>
    import {mapState,mapMutations} from 'vuex'
    export default {
        name: 'scorePage',
        data(){
            return {
                kSchoolId: this.$common.getSession("userData").school.id,                
                kSchoolYearId: this.$common.getSession("userData").schoolYear.id,classId: '123',
            }
        },
        computed:{
            ...mapState('semester',['newSemester']),
        },
        methods: {
            // 下载excel表格            
            downloadExcel() {                
                let params = {                    
                    kSchoolId: this.kSchoolId,                    
                    kSchoolYearId: this.kSchoolYearId,                    
                    kSemesterId: this.newSemester.id,                    
                    kClassesGroupId: this.classId,                
                }                
                params.scoreClassesGroupId = this.tableFirstId;                
                if(this.orderCodeNum != -1) {                    
                    params.orderCode = this.orderCodeNum;                
                }                
                if(this.courseRankIndex != -1) {                    
                    params.kCourseId = this.scoreCourseId;                
                }                
                let url = `${baseUrl}/api/score/classes/group/export`;                
                url += '?'                
                for(const item in params){                    
                    url += encodeURIComponent(item) + '=' + encodeURIComponent(params[item]) + '&';                
                };                
                // responseType: "arraybuffer"将后台返回的默认json改为二进制                
                axios.post(url,{responseType: "arraybuffer"}).then(res=>{                    
                    let result = res.data;                    
                    let url =  window.URL.createObjectURL(new Blob([result]));//处理文档流                    
                    // let fileTye = url.match(/.+\/(.+)$/)[1];                    
                    let link = document.createElement('a');                    
                    link.style.display = 'none';                    
                    link.href = url;
                    
                    // link.download = fileTye;                    
                    link.download = '成绩汇总表.xls';                    
                    document.body.appendChild(link);                    
                    link.click();   
                    document.body.removeChild(link);             
                })            
            }
        }
    }
</script>

此方法并不局限于post请求,get请求也一样可以


最后,分享篇关于导入二进制流文件的文章

zhuanlan.zhihu.com/p/51941539?…  


JS前端创建html或json文件并浏览器导出下载

www.zhangxinxu.com/wordpress/2…