文件上傳一般有兩種方式:文件流上傳和base64方式上傳,毫無疑問,當進行大文件上傳時候,轉為base64是不現實的,因此用formData方式結合文件流,直接上傳到服務器
本文主要結合vue的來講解,主要知識點有“promise函數、formData對象使用、ajax異步上傳、文件切割
//1、這里先在vue的Data中定義幾個上傳所需要的變量 taskId: '' //區分分包文件名 bytesPerPiece: 1 * 1024 * 1024, // 每個文件切片大小定為1MB . totalPieces: 0,//文件切片個數 blob: '',//原始文件 start: 0,//第一個分片 end: 0,//最后一個分片 index: 1,//分片次序 filesize: 0,//文件大小 chunk: 0,//文件分片 formData: new FormData(),//后端header所需對象
// 2、分片上傳方法--這里的ajax如果項目封裝了axios可以直接改為axios,以避免使用jquery,使項目體積增大 fileSlice(){ return new Promise((resolve, reject) => { var _this = this; if (this.start < this.filesize) { //判斷剩余文件大小,大於起始值執行切割操作 this.end = this.start + this.bytesPerPiece; //規定分片文件節點 if (this.end > this.filesize) { //判斷是否是最后一個切片 this.end = this.filesize; } this.chunk = this.blob.slice(this.start, this.end); //切割文件 this.sliceIndex = this.index; this.percentage = parseInt((this.sliceIndex / this.totalPieces) * 100); // 進度提示,如果不需要進度可省略 if(this.percentage == 0){ // 這里是因為當文件過大時候,避免進度顯示過慢,影響用戶體驗 this.percentage = 1; } console.log('sliceIndex', this.sliceIndex, 'this.percentage', this.percentage); this.formData = new FormData(); this.formData.append('file', this.chunk); $.ajax({ type: 'post', url: //后端接口 headers: { //后端所需參數 'jwt-token': Auth.getJwtToken(), taskId: _this.taskId, chunk: _this.sliceIndex, size: _this.chunk.size, chunkTotal: _this.totalPieces, orginFileName: 'uploadFile' }, //傳入組裝的參數 data: this.formData, dataType: 'json', async: true, cache: false, //上傳文件不需要緩存 contentType: false, //需設置為false。因為是FormData對象,且已經聲明了屬性enctype="multipart/form-data" processData: false, //需設置為false。因為data值是FormData對象,不需要對數據做處理 success: function(res) { if (_this.sliceIndex == _this.totalPieces) { //判斷是否為最后一個文件,如果是,賦值后端輸出路徑 像服務端上傳文件 _this.upPath = res.data.path; _this.buttonLoading = false; } if(res.code == 0){ resolve('0'); }else{ _this.clearUploadFile(); reject(res.message); } }, error: function(res) { //異常判斷 reject('上傳文件失敗,請重新上傳!', this.fileList = []); _this.$message({ message: res.message, type: 'error' }); return 'break'; } }); } _this.start = this.end; _this.index++; }); }, async fileUpload(file) { //此處主要給文件加32位隨機數 console.log(file.file); this.blob = file.file; this.filesize = this.blob.size; this.totalPieces = Math.ceil(this.filesize / this.bytesPerPiece); function randomWord(randomFlag, min, max) { // eslint-disable-next-line one-var let str = '', range = min, arr = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z' ]; // 隨機產生 if (randomFlag) { range = Math.round(Math.random() * (max - min)) + min; } for (var i = 0; i < range; i++) { let pos = Math.round(Math.random() * (arr.length - 1)); str += arr[pos]; } return str; } this.taskId = randomWord(false, 32); for(let i = 0; i < this.totalPieces; i++){ let ttt = await this.fileSlice().catch((res) => { this.$message({ message: res, type: 'error' }); }); if(ttt != 0){ break; } } },
//3、中止文件上傳 clearUploadFile(){ // buttonLoading this.buttonLoading = false; this.totalPieces = 0; this.blob = ''; this.start = 0; this.end = 0; this.index = 1; this.filesize = 0; this.chunk = 0; this.percentage = 0; // 清空文件表 this.fileList = []; const mainImg = this.$refs.upload; if (mainImg && mainImg.length) { mainImg.forEach(item => { // item.uploadFiles.length = 0; item.clearFiles(); }); } },