前言:本文使用 服务端生成PutObject所需的签名URL, 前端凭借签名URL,不依赖oss sdk 直接上传文件。
之前项目都是前端上传文件到服务器,然后由服务器上传到oss,这种情况呢,数据要在网络上传输两次,会导致网络资源浪费,增大服务器的开销,本次采用前端直传的方式来实现图片上传。
原理:
参考:阿里云文档
代码实现
<template>
<!-- 上传图片组件 -->
<el-upload
v-model="imgUrl"
class="single-uploader"
:show-file-list="false"
list-type="picture-card"
:before-upload="handleBeforeUpload"
:http-request="uploadFile"
>
<img v-if="imgUrl" :src="imgUrl" class="single-uploader__image" />
<el-icon v-if="!progress.showProgress && !imgUrl" class="single-uploader__icon"><Plus /></el-icon>
<el-progress v-if="progress.showProgress" type="circle" :percentage="progress.upProgress" />
</el-upload>
</template>
<script setup lang="ts">
import { UploadRawFile, UploadRequestOptions, ElMessage } from "element-plus";
import { reactive, ref } from "vue";
import { uploadFileApi, ossUploadApi } from "@/api/file/index";
import { RuleFileForm } from "@/api/file/types";
const imgUrl = ref<string>();
const uploadFileInfo = reactive<RuleFileForm>({
filename: '',
prefix: ''
})
// 定义上传文件进度条
const progress = reactive({
upProgress: 0,
showProgress: false,
});
/**
* 自定义图片上传
*/
async function uploadFile(options: UploadRequestOptions): Promise<any> {
uploadFileInfo.filename = options.file.name;
uploadFileInfo.prefix = 'user/logo';
progress.showProgress = true;
uploadFileApi(uploadFileInfo).then((res)=>{
if(res.code == 0){
const { accessUrl, uploadSignedUrl } = res.data;
ossUploadApi(uploadSignedUrl, options.file, (progressEvent: any) => {
progress.upProgress = (progressEvent.loaded / progressEvent.total * 100) | 0 // 上传进度条设置
}).then(r => {
console.log(r);
imgUrl.value = accessUrl;
progress.showProgress = false;
})
}
})
}
/**
* 限制用户上传文件的格式和大小
*/
function handleBeforeUpload(file: UploadRawFile) {
if (file.size > 2 * 1048 * 1048) {
ElMessage.warning("上传图片不能大于2M");
return false;
}
return true;
}
</script>
import request from "@/utils/request";
import { FileInfo, FileInfoRes } from "./types";
/**上传文件 */
export function uploadFileApi(uploadFileInfo: FileInfo){
return request<FileInfoRes>({
url: "/api/file/get-upload-url",
method: "post",
data: uploadFileInfo,
});
}
export function ossUploadApi(uploadSignedUrl: string, file: any, progressEvent: any) {
return request({
url: uploadSignedUrl,
method: 'put',
headers: {
"Content-Type": "" // 必须设置为空,不然会报403错误
},
data: file,
onUploadProgress: progressEvent,
})
}
上传成功!