Vue实现阿里云oss文件上传(服务端签名后直传)

最近开发项目过程中需要有一些图片上传的功能,本想用普通的上传方式,即后台提供上传的地址,前端直接调用的方法,但此方法有一点缺点,用户数据需先上传到应用服务器,之后再上传到OSS。网络传输时间比直传到OSS多一倍。如果用户数据不通过应用服务器中转,而是直传到OSS,速度将大大提升。为了提高上传效率,决定使用服务端签名后直传的方法来实现

服务端签名后直传的原理如下:

  • 用户发送上传Policy请求到应用服务器
  • 应用服务器返回上传Policy和签名给用户
  • 用户直接上传数据到OSS

1、先创建一个upload.vue进行封装方便其它组件使用

<template>
    <div class="el-upload-model">
        <el-upload class="el-avatar-uploader" 
            action="#"
            ref="upload"
            :show-file-list="false"
            :http-request="handleUploadImg"
            :on-success="handleAvatarSuccess"
            :before-upload="beforeAvatarUpload">
            <img class="el-avatar" v-if="pictureUrl" v-lazy="pictureUrl">
            <i v-else class="el-upload-icon">
                <i class="el-icon-plus avatar-uploader-icon"></i>
            </i>
        </el-upload>
        <div class="el-progress-grid">
            <el-progress class="el-progressbar" 
                type="circle" 
                v-if="progressFlag"
                color="#67c23a"
                :percentage="progressPercent">
            </el-progress>
        </div>
    </div>
</template>
<script>
 	// 获取阿里云oss token api
    import { getOssToken } from '@/api/user'

    export default {
        name: 'uploadCompt',
        props: {
            pictureUrl: {
                type: String,
                default: ''
            }
        },
        data () {
            return {
                imageUrl: '',
                progressFlag: false,
                progressPercent: 0
            }
        },
        methods: {
        	// 截取上传文件后缀
            getSuffix(filename) {
                let pos = filename.lastIndexOf('.')
                let suffix = ''
                if (pos != -1) suffix = filename.substring(pos)
                return suffix
            },
            // 生成随机数
            randomString(len) {
                len = len || 32
                const chars = 'ABCDEFGHJKMNPQRSTWXYZabcdefhijkmnprstwxyz2345678'
                const maxPos = chars.length
                let pwd = ''
                for (let i = 0; i < len; i++) {
                    pwd += chars.charAt(Math.floor(Math.random() * maxPos))
                }
                return pwd
            },
            beforeAvatarUpload(file) {
                const isJPG = file.type === 'image/png' || file.type === 'image/gif' || file.type === 'image/jpg' || file.type === 'image/jpeg' || file.type === 'image/svg+xml'
                const isLt1M = file.size / 1024 / 1024 < 1

                const isSize = new Promise((resolve, reject) => {
                    let width = 1080
                    let height = 540
                    let _URL = window.URL || window.webkitURL
                    let img = new Image()
                    img.onload = () => {
                        let valid = img.width <= width && img.height <= height
                        valid ? resolve() : reject()
                    }
                    img.src = _URL.createObjectURL(file)
                }).then(() => {
                    return file
                }).catch((err) => {
                    this.$message.warning('上传的图片像素必须是小于或等于1080px * 540px!')
                    return Promise.reject()
                })

                if (!isJPG) {
                    this.$message.warning('上传的图片只能是PNG、GIF、JPG、JPEG、SVG格式!')
                } else if (!isLt1M) {
                    this.$message.warning('上传的图片大小不能超过1MB!')
                }
                
                return isJPG && isLt1M && isSize
            },
            handleUploadImg(file) {
                getOssToken().then((res) => {
                    if (res.code && res.code === 200) {
                        let picName = this.randomString(10) + this.getSuffix(file.file.name)
                        let keyValue = res.data.dir + '/' + picName
                        //注意formData里append添加的键的大小写
                        let formData = new FormData()
                            formData.append('name', file.file.name) // 文件名称
                            formData.append('key', keyValue) // 存储在oss的文件路径
                            formData.append('OSSAccessKeyId', res.data.accessid) // //accessKeyId
                            formData.append('policy', res.data.policy) // policy
                            formData.append('Signature', res.data.signature) //签名
                            formData.append('success_action_status', 200)
                            formData.append('file', file.file, file.file.name) // 如果是base64文件,那么直接把base64字符串转成blob对象进行上传即可

                        this.progressFlag = true
                        return new Promise((resolve, reject) => {
                            this.$axios.post(res.data.accessHost, formData, {
                                headers: { 
                                    'Content-Type': 'multipart/form-data'
                                },
                                // 图片上传进度
                                onUploadProgress: (progressEvent) => {
                                    this.progressPercent = Math.floor((progressEvent.loaded * 100) / progressEvent.total)
                                }
                            }).then((rep) => {
                                if (rep.status === 200) {
                                    this.imageUrl = res.data.accessHost + '/' + keyValue
                                    this.$emit('uploadSuccess', this.imageUrl)
                                    console.log('Uploaded successfully', rep)
                                    if (this.progressPercent >= 100) {
                                        this.progressFlag = false
                                        setTimeout(() => {
                                            this.progressPercent = 0
                                        },1000)
                                    }
                                }
                                resolve(rep)
                            }).catch((err) => {
                                reject(err)
                            })
                        })
                    }
                }).catch((err) => {
                    console.log(err)
                })
            },
            handleRemove(file) {
                this.$refs.upload.abort()
                this.$message({ 
                    message: '成功移除' + file.name, 
                    type: 'success'
                })
            },
            handleAvatarSuccess(res, file) {
                this.imageUrl = URL.createObjectURL(file.raw)
            }
        }
    }
</script>
  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值