美文网首页
vue+element-ui+oss直传方案示例

vue+element-ui+oss直传方案示例

作者: 不想做肥宅的薛小皮 | 来源:发表于2020-06-02 11:31 被阅读0次

    最近项目开发商品库模块,有一个商品图片上传的功能,需要用到阿里云的oss直传服务器技术,最终实现的过程比较坎坷,记录下来以便后期使用。

    本次项目用到的UI框架是element UI,直传过程是先请求后台,后台去进行签名,然后返回签名信息给我,我再拿着签名信息和其他图片数据进行直传,由于阿里云的文档中只有js的demo,应用到vue中还需要进一步的封装,所以索性通过查阅相关数据以及自己摸索,通过element UI的上传组件实现了oss直传,代码如下所示:

    <el-upload class="oss-upload" ref="upload1" 
               :auto-upload="false" :show-file-list="false" 
               accept=".jpg,.jpeg,.png,.JPG,.JPEG,.PNG"
               action:on-change="imgPreview" list-type="picture">
        <el-button size="small" type="primary">选择列表图</el-button>
        <div slot="tip" class="el-upload__tip">只能上传jpg/png文件,且不超过2M</div>
    </el-upload>
    
    //判断图片格式和大小
    imgPreview(file) {
        if (file.status === "ready") {
            const isJPG = file.raw.type === 'image/jpeg' || file.raw.type === 'image/png'
            const isLt5M = file.raw.size / 1024 / 1024 < 2
            if (!isJPG) {
                this.$message.error('上传图片只能是 PNG、JPG 格式!')
                return false
            } else if (!isLt5M) {
                this.$message.error('上传图片大小不能超过2MB!')
                return false
            } else {
                //合适的图片会存入带上传图片数组
                this.fileList.push(file)
            }
        }
    },
    //获取上传图片的名字
    get_suffix(filename) {
        let pos = filename.lastIndexOf('.')
        let suffix = ''
        if (pos != -1) {
            suffix = filename.substring(pos)
        }
        return suffix
    },
    //生成32位随机字符附在名字前面
    random_string(len) {
        len = len || 32
        let chars = 'ABCDEFGHJKMNPQRSTWXYZabcdefhijkmnprstwxyz2345678'
        let maxPos = chars.length
        let pwd = ''
        for (let i = 0; i < len; i++) {
            pwd += chars.charAt(Math.floor(Math.random() * maxPos))
        }
        return pwd
    },
    //图片上传拿签名
    picUpload(file,type) {
        let fileObj = file
        let data = this.upParams;//提前请求拿到的签名信息
        let ossData = new FormData()//创建oss数据对象
        ossData.append('name', fileObj.name)
        let filename = fileObj.name
        let picName = this.random_string(32) + this.get_suffix(filename)
        let keyValue = data.dir + picName
        if(type == 'list'){
            this.upList_picture.push(picName)
        }else if(type == 'detail'){
            this.upDetail_picture.push(picName)
        }
        ossData.append('key', keyValue)
        ossData.append('policy', data.policy)
        ossData.append('OSSAccessKeyId', data.accessid)
        ossData.append('success_action_status', 200)
        ossData.append('signature', data.signature)
        ossData.append('file', fileObj, fileObj.name)
    //实际项目中是将图片存在待上传列表中,点击确定后先进行上传,然后再把上传的图片信息发给后台保存,
    //这里的问题就是如果图片还没有上传成功就把数据发给后台的话,就会导致图片访问不到。
    //所以这里是通过返回一个promise,后面通过promise.all方法来判断是否全部上传成功。具体代码再下一个片段中
        return new Promise((resolve, reject) => {
            this.$http.post(data.host, ossData, {
                headers: {
                    'Content-Type': 'multipart/form-data'
                },
            }).then(res => {
                resolve(res);
            }).catch(error => {
                reject(error);
            })
        });
    }
    

    判断图片是否上传成功代码:

    let promistArr = []
    //fileList是待上传列表的数组,里面有图片文件的相关数据,picUpload是前面的上传函数
    this.fileList.forEach(list1 => {
        if (list1.raw) {
            //将函数return的结果push进数组
            promistArr.push(this.picUpload(list1.raw,'list'))
        }
    })
    //判断数组中所有promis的结果并进行相关处理
    Promise.all(promistArr).then((result) => {
        console.log(result)
    }).catch((error) => {
        console.log(error)
        this.$message({
            type: 'warning',
            message: "图片上传失败"
        });
    })
    
    走到这里可以正常情况下是可以成功了,但我遇到了一个问题,就是每次上传之后总会报跨域错误,查看network发现图片已经上传成功了,但报错就无法获取结果,也就无法进行后面的操作了
    控制台报错信息
    后来经过一番查阅,找到了这篇文章,情况相似,于是尝试性的对请求进行了一些改动,果然成功了
    CORS: credentials mode is 'include'
    return new Promise((resolve, reject) => {
        this.$http.post(data.host, ossData, {
            headers: {
                'Content-Type': 'multipart/form-data'
            },
            withCredentials: false //这里修改了withCredentials为false
        }).then(res => {
            resolve(res);
        }).catch(error => {
            reject(error);
        })
    });
    
    成功上传之后的返回结果

    因为项目涉及到登录状态问题,每次请求需要带着cookie去判断,超时后就要重新登录,结果导致了图片上传的问题,不过幸好经过查阅之后解决了这个问题,记录下来方便自己学习的同时也希望能帮到其他被困扰的朋友。

    个中解释纯属个人理解,有不同见解的朋友可以评论讨论

    相关文章

      网友评论

          本文标题:vue+element-ui+oss直传方案示例

          本文链接:https://www.haomeiwen.com/subject/gkuyzhtx.html