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

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

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


    选择列表图
    
只能上传jpg/png文件,且不超过2M
//判断图片格式和大小
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直传方案示例)