平时在做 oss 上传时,通过都是单个文件上传,但是前几天工作时涉及到多个文件的上传,在所有文件都上传完成后才能再做后续的代码执行。于是在原有的oss上传基础上添加for循环去挨个上传。
介绍一下,oss 的上传可以有两种:
- 一种是把所有的文件上传给后端,由后端去传到阿里云oss上,这样不涉及到向后端获取accessKeyId 和bucket等,没有key泄露的风险(适用于C端客户)。
- 一种是向后端调接口获取key等数据,存储在本地,需要的时候调用就可以了,key值设置失效时间,一段时间过后,再向后端获取新的key值,减少key泄露(适用于B端客户)。
第一种,我们就不过多介绍了,就平常的调用上传接口,这篇文章主要介绍第二种
所用到的框架:vue + typescript + element-ui +ali-oss
效果:
<!--
on-preview :点击文件列表中已上传的文件时的钩子
on-remove :文件列表移除文件时的钩子
on-change: 文件状态改变时的钩子,添加文件、上传成功和上传失败时都会被调用
disabled: 是否可上传、添加、删除等
-->
<el-row class="toolbar">
<el-upload
action="#"
:auto-upload="false"
list-type="picture-card"
ref="modelFormId"
:on-preview="handlePictureCardPreview"
:on-remove="handleRemove"
:on-change="onChangeFileValid"
:disabled="isLook"
>
<i class="el-icon-plus"></i>
</el-upload>
<el-dialog :visible.sync="dialogVisible">
<img width="100%" :src="dialogImageUrl" alt="" />
</el-dialog>
<el-button @click='upload'>开始上传</el-button>
</el-row>
- 该引入的插件和文件
<script lang="ts">
import Vue from "vue";
import { Component, Prop, Watch } from "vue-property-decorator"; // typescript导入组件装饰器
// 自己写的生成的36位文件名称id标识
import { Common } from "@/assets/js/common";
// 安装 ali-oss 这也是文件上传阿里云时需要用到的
import OSS from "ali-oss";
// 向后端获取oss key的接口
import { getPublicUpOssSTS } from "@/api/download";
@Component({})
export default class Upload extends Vue {
ossComPath: string = "ictr-tb-commonservice-test"; // 上传文件时文件所在的文件夹地址
dialogImageUrl: string = ""; // el-upload 放大文件时的url地址
dialogVisible: boolean = false; // el-upload 是否正在预览文件
common: any = new Common(); // new 一下common
pathName: string = ""; // 上传文件的id
isLoaderVisible: boolean = false; // 上传文件时的标识
fullscreenLoading: boolean = false; // 正在上传
file: any = undefined;
ossClient: any = {
region: "oss-cn-beijing",
accessKeyId: "",
accessKeySecret: "",
bucket: "",
stsToken: ""
};
fileList: any[] = [];
// 点击开始上传按钮
upload() {
const loading = this.$loading({
lock: true,
text: "Loading",
spinner: "el-icon-loading",
background: "rgba(0, 0, 0, 0.7)"
});
this.isLoaderVisible = true;
// 判断签名是否过期,如果过期再次向后端获取签名,也就是key
this.setUploadParam().then(
async status => {
loading.close();
if (status === 200) {
// 开始调用上传方法
this.multipartUpload();
}
},
req => {
loading.close();
}
);
}
// 真正开始上传
async multipartUpload(param) {
if (this.fileList.length !== 0) {
this.client = new OSS(this.ossClient);
let storeAsList: any[] = [];
//遍历要上传的文件,设置文件唯一名称
this.fileList.forEach((m, index: number) => {
// 自定义id键和自定义名称
const name = this.common.guid() + this.common.getFileExtendingName(param.name);
storeAsList.push({
storeAs: "adcp/DefaultFilePath/fileAnalysisTempSource/" + name,
m
});
});
// 等待全部上传成功
await Promise.all(
storeAsList.map((file, i) => {
return this.multiBackPath(file.storeAs, file.m);
})
);
//此时已经全部上传成功了
this.$message.success("所有文件上传成功!");
}
}
multiBackPath(storeAs, param) {
return new Promise((resolve, reject) => {
this.client
.multipartUpload(storeAs, param.raw)
.then(result => {
resolve(result);
})
.catch(err => {
if (!this.client.isCancel()) {
this.isLoaderVisible = false;
this.$message.warning("上传失败-");
reject();
}
});
});
}
文件上传之前判断签名是否过期
setUploadParam() {
// 判断本地是否有已存在oss
let ossData = JSON.parse(localStorage.getItem("ossdata") as any);
return new Promise((resolve, reject) => {
if (ossData !== null && new Date(ossData.Expiration) > new Date()) {
this.ossClient.accessKeyId = ossData.AccessKeyId;
this.ossClient.accessKeySecret = ossData.AccessKeySecret;
this.ossClient.stsToken = ossData.SecurityToken;
this.ossClient.bucket = this.ossComPath;
resolve(200);
} else {
// 如果本地oss key已过期,再向后端获取
getPublicUpOssSTS().then(
(res: any) => {
let json = JSON.parse(JSON.stringify(res.data));
this.ossClient.accessKeyId = json.AccessKeyId;
this.ossClient.accessKeySecret = json.AccessKeySecret;
this.ossClient.stsToken = json.SecurityToken;
this.ossClient.bucket = this.ossComPath;
localStorage.setItem("ossdata", JSON.stringify(json));
resolve(200);
},
() => {
reject(400);
}
);
}
});
}
// 文件成功添加在el-upload时触发的钩子
onChangeFileValid(file) {
let xls = file.name.split(".").pop();
if (["jpg", "png"].includes(xls)) {
// 每添加一个文件,就push到 fileList集合中
this.fileList.push(file);
} else {
(this.$refs.modelFormId as any).clearFiles();
this.$message.error("文件只能上传.jpg或.png的文件!");
}
return false;
}
//
// 删除上传的文件
handleRemove(file, fileList) {
this.fileList = fileList;
}
handlePictureCardPreview(file) {
this.dialogImageUrl = file.url;
this.dialogVisible = true;
}
}
</script>