vue中图片上传到阿里云oss记录

最近项目需求,做一个图片上传到阿里云oss的功能,由于之前没做过这样的功能,所以也是查阅了不少资料,边写demo边测试把基本功能完成了。现在来记录下,没做过的童鞋也可以简单参考下。我的使用场景是在vue项目中结合iview框架的上传组件来实现功能。

首先给大家一篇阿里云的文档 web端直传实践,它里面给出了三个上传的例子,如下图:


最开始我们后端让我自己看看这些例子,也没决定好用哪种方式,而我选择尝试的是第一种方式,因为不需要后端直接参与。那我就先从第一种方式开始说起,在这之前你需要开通好阿里云的对象存储功能,并新建了一个Bucket,这些我就直接略过了,给个文档:使用阿里云OSS

JavaScript客户端签名直传

这种方式不需要后端直接参与,你只需要配置好阿里云oss的后台就好,非常方便。但是客户端通过JavaScript把AccesssKeyID和AccessKeySecret写在代码里面有泄露的风险。关于AccesssKeyID和AccessKeySecret,参考上面给的文档里的介绍。

每种方式官方都给出了demo代码,你可以下载下来参考一下,不过我觉得例子代码有点多,就没用他那种方式。阿里云提供了一个sdk可以帮助我们来实现文件上传。这里是SDK参考

我是直接使用它的cdn引入的,在index.html中直接引入:

1
<script src="https://gosspublic.alicdn.com/aliyun-oss-sdk.min.js"></script>

之前说了我是结合iview框架的上传组件的,我把上传功能单独写成了一个组件,为防止大家看的难受,这里只贴上部分核心代码:

template:

1
2
3
4
5
6
7
8
9
10
11
12
13
// iview上传组件
<Upload
:before-upload="handleBeforUpload" // before-upload 上传文件之前的钩子,参数为上传的文件
action=""
>
<Button icon="ios-cloud-upload-outline">选择文件</Button>
</Upload>

// 显示选择的图片名
<div v-if="file">已选择文件:{{file.name}}

// 手动点击上传
<Button @click="upLoad">点击上传</Button>

script:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
data(){
return {
file:'' // 选择上传的文件
}
},

methods:{
// 上传之前的操作
handleBeforUpload (file) {
this.file = file // 将回调的文件信息存入data.file
return false // 返回false,表示手动上传,取消默认的自动上传
},

// 点击上传按钮触发上传操作
upload(){
// sdk提供的创建客户端实例方法
const client = new OSS.Wrapper({
region: 'oss-cn-hangzhou', // 创建Bucket时会选择不同地区,根据自己的选择填入对应名称
accessKeyId: '********', // 填入你的accessKeyId
accessKeySecret: '********', // 填入你的accessKeySecret
bucket: '***' // 填入你的bucket名
})

const Name = this.file.name
const suffix = Name.substr(Name.indexOf('.')) // 文件后缀
const filename = Date.parse(new Date()) + suffix // 组成新文件名

client.multipartUpload(filename, this.file).then(res => { // 上传
console.log('上传成功:',res)
// ... 你的操作,可以拼接图片url,用于显示等...
}).catch(err => {
console.log('上传失败:', err)
})
}
}

以上就是一个最简单的上传图片功能,总结就是:取消iview组件默认的自动上传功能,选择手动上传,在上传之前拿到图片信息,在点击上传按钮时,借助sdk提供的方法,填入你的OSS参数,最后将图片上传。上传成功之后,可以到OSS管理控制台的文件管理中看到图片信息。

服务端签名直传并设置上传回调

我和后端最终选择的方式就是这种,至于为啥,显然上面那种方法看起来不那么安全,更多的区别还是去看文档介绍的。
同样的,这种方法也提供了demo,但是我依旧没用它的方式去实现我的功能。我还是先贴上少部分核心的代码,其中上面的template部分不用变,主要来看看js部分的实现:

首先handleBeforUpload中,我们需要加一步获取参数的方法,并组成要上传的数据

1
2
3
4
5
6
7
8
handleBeforUpload (file) {
this.file = file
// 获取上传文件前服务器给的参数
this.$store.dispatch('handleGetAllOss').then(res => {
this.setParams(res.data) // 组装我们要上传的数据,方法的代码在下面
})
return false
},

我使用了vuex,所以请求都写在了actions里,handleGetAllOss这个action里会请求一些上传需要的参数,请求地址是需要后端提供的,所以如果用这种方式的话,后端大佬的大腿要抱牢。关于请求我就不多说了,就简单发个ajax的get请求拿到参数就好。想要知道会有哪些参数,我们重点来看setParams这个方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
setParams (data) {
// data 是我上一步骤传过来的参数object

// 这个url是要上传时的地址,存在data的host上
this.url = data.host

const Name = this.file.name
const suffix = Name.substr(Name.indexOf('.')) // 文件后缀
const filename = Date.parse(new Date()) + suffix // 组成新的文件名

// 新建formData对象,使用append方法添加字段,在data中拿的都是请求回来的参数
let formData = new FormData()
formData.append('key', data.dir + storeAs)
formData.append('policy', data.policy)
formData.append('OSSAccessKeyId', data.accessid)
formData.append('success_action_status', '200')
formData.append('callback', data.callback)
formData.append('signature', data.signature)

formData.append('name', Name) // 文件名
formData.append('file', this.file) // 文件,选择时存在data上

this.formData = formData // 将formData对象存入data中,方便后续使用
},

现在我们有了要上传的数据this.formData,有了上传地址:this.url,现在只要使用ajax的post请求就好了,当点击上传按钮时,调用upload方法:

1
2
3
4
5
6
7
8
upload(){
this.$store.dispatch('handleUploadImg', { url: this.url, data: this.formData }).then(res => {
console.log('上传成功:',res)
// 你的操作
}).catch(err => {
console.log('上传失败:',err)
})
}

我还是把我的啰嗦的代码贴出来吧

handleUploadImg方法:

1
2
3
4
5
6
7
8
9
10
11
12
// 上传
handleUploadImg ({ commit }, { url, data }) {
return new Promise((resolve, reject) => {
uploadImg({ url, data }) // 方法在下面
.then(res => {
resolve(res)
})
.catch(err => {
reject(err)
})
})
}

uploadImg方法:

1
2
3
4
5
6
7
8
const uploadImg = ({ url, data }) => {
return axios.request({ // axios.request 方法是简单的对axios的封装,看这配置也应该不需要多介绍
url,
data,
method: 'post',
headers: { 'Content-Type': 'multipart/form-data' }
})
}

上面的流程就是这种上传方式的简单实现,你不必按照我的方式来,总结一下就是:

  1. 请求后端给你的地址,拿到上传时必要的参数
  2. 将获取的参数拼装至formData
  3. 使用post方法发送请求,带上formData数据,请求地址在步骤1的参数里,host参数。
  4. post请求成功后的回调,是后端可控的,我让后端加了一个图片名返回,自己拼接图片url。

这个过程需要后端的参与。

图片处理(缩略图)

本来没这步的,想想还是写上来,觉得阿里云这个功能挺好用的。

通过上面的两种方式可以成功上传图片到阿里云的对象存储,然后就可以使用url访问图片了。一般上传成功后,在页面上会显示一个缩略图,这个缩略图不仅仅是你设置宽高看起来小,实际上它真的可以变小。在阿里云OSS管理控制台,点击图片处理,点击新建样式,你会看到下面这样:

如图你可以在右侧添加一个图片样式,比如可以选择缩略比例,设置好后点确定就会生成一个图片样式,我图中已经有一个min_img名的样式,表示缩略图的意思,这样在我想要访问某个图片的缩略图时,在图片url后面加上?x-oss-process=style/min_img这个后缀就好了,min_img替换成你设置的样式名。

结语

本人也是刚接触这个,实现的也是最基本的功能,实现过程也可能并不正确。有做过这个的童鞋们可以多给点意见,谢谢。🙏