前言:本文使用 服务端生成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, }) }
上传成功!