# 写在前面
做项目遇到一个好玩的,用别人平台的文件上传的接口,通过页面查看了以后,模拟他们的请求接口结果死活调不通(也不知道他们是怎么写的),后面问他们要了一份接口文档才弄出来。一看是采用的文件分割异步上传。。。。后台有没有更好的方法,反正我觉得这种方法不太好,我说的是这种接口方式。因为有点意思(另类)。所以。。。。。。
vue文件
<template>
<div class="my-terminaldev">
<el-form ref="form" :model="form" :rules="rules" label-width="80px">
<el-form-item label="文件" prop="file">
<div class="upload-content">
<el-upload
class="upload-demo"
accept="file"
ref="upload"
multiple
action="#"
:http-request="myFileUpload"
:before-upload="beforeUpload"
:before-remove="beforeRemove"
:file-list="fileList"
:auto-upload="true"
:limit="1">
<el-button size="small" type="primary">点击上传</el-button>
</el-upload>
<!--我还给他写了一个及其简陋的上传loading,这个可以略过-->
<el-progress v-if="uploadProgress" :percentage="(fileDataUploadList.length && fileDataList.length) ? ((fileDataUploadList.length / fileDataList.length)*100) : 0" :status="(fileDataUploadList.length / fileDataList.length)===1 ? 'success':'exception'"></el-progress>
</div>
</el-form-item>
<div style="text-align:center" v-if="upDataBtnShow"><el-button type="primary" @click="onSubmit(form)">确定更新</el-button></div>
</el-form>
</el-dialog>
</div>
</template>
<script>
// 这个是他们的一个初始化上传的接口,上传之前请求这个接口会返回一个上传文件的地址 'uploadUrl',一个请求合并文件的地址 'completeMultipartUrl'
import { initFileUpload } from "@/api/xxx"
import axios from 'axios'
export default {
name: 'terminaldev',
data(){
return {
form:Object,
// 文件上传的地址
uploadUrl: '',
// 上传完成请求后台合并文件的地址
completeMultipartUrl: '',
// 文件分割以后的总列表数据
fileDataList: [],
// 文件上传成功以后的数据,上传多少个块push多少
fileDataUploadList: [],
// 原始文件数据
fileData: '',
// 这个是为了等文件全部上传以后我才显示下一步操作按钮
upDataBtnShow: false,
// 开始隐藏上传进度条
uploadProgress: false,
// 自定义上传请求头
uploadHeaders: {
'Accept':'application/json',
'Authorization':localStorage.getItem("token"),
}
// 文件列表
fileList:[]
}
},
methods:{
// 上传文件之前
beforeUpload(file, fileList) {
this.uploadProgress = true
this.fileData = file
// 调用函数分割文件 我这里是分割成不超过20M的文件快
this.fileDataList = this.createFileChunk(file,1024*1024*20)
return new Promise((reslove, reject)=>{
this.fileUpLoad(reslove, reject);
})
},
// 自定义文件上传的模式,方法
myFileUpload(params){
/** 这里采用了循环请求,等全部循环上传请求完成以后再去执行合并请求的操作 Promise.all
* 参数既有url参数也有body参数
*/
let promiseAll = this.fileDataList.map(item => {
let formData = new URLSearchParams()
formData.append('partNumber', item.partNumber)
return new Promise((resolve,reject) => {
axios({
method: 'post',
headers: {
'Authorization': localStorage.getItem("token"),
},
params: formData,
url: `${this.uploadUrl}`,
data: item.file,
})
.then(res=>{
this.fileDataUploadList.push(res.data.data)
resolve(res.data.data)
})
.catch(err=>{
reject(err)
})
})
})
Promise.all(promiseAll).then(resDataAll => {
// 请求合并文件
axios({
method: 'post',
headers: {
'Authorization': localStorage.getItem("token"),
},
url: `${this.completeMultipartUrl}`,
data: resDataAll,
}).then(res=>{
// 合并成功以后展示下一步的操作模块(其实是一个保存表单)
this.upDataBtnShow = true
})
})
},
// 初始化上传接口的函数,再上面上传之前调用的
fileUpLoad(reslove, reject) {
const paramsData = {
multipartUpload: true, // 是否是文件分步,分块上传
name: this.fileData.name,
size: this.fileData.size,
}
initFileUpload(paramsData).then(res => {
const uploadUrl = res.data.data.uploadUrl
const completeMultipartUrl = res.data.data.completeMultipartUrl
// 文件上传的请求地址
this.uploadUrl = uploadUrl
// 合并文件上传的请求地址
this.completeMultipartUrl = completeMultipartUrl
reslove();
}).catch((err)=>{
reject(err)
})
},
// 文件分割的方法
createFileChunk(file, size = chunkSize) {
const fileChunkList = [];
let count = 0;
let num = 1
while (count < file.size) {
fileChunkList.push({ file: file.slice(count, count + size), partNumber: num });
count += size;
num++
}
return fileChunkList
},
// 移除已上传的文件
beforeRemove(file, fileList) {
return this.$confirm(`确定移除 ${ file.name }?`);
},
}
}
</script>