七牛云对象存储 oss 之上传图片(2024最新教程)

七牛云对象存储 oss 之上传图片(2024最新教程)

1 背景

最近在做一个商城项目,其中上传一些商品需要使用云存储来保存图片,在国内各个厂商都有对应服务,七牛云是国内算是挺不错的图片存储服务器,免费用户能拥有 10G 空间,每个月 10G 的下载流量,对于个人用户用于做个小博客,小网站来说,已经够了。但是官方文档比较零散,就打算写一篇文档记录一下,方便

2 七牛云的优势

在选择云存储服务时,了解七牛云的优势和劣势还是有必要的:

总体评价

适用范围:

七牛云适用于中小型企业和创业项目,注重简单易用、低成本、全球加速的应用场景。

灵活性:

七牛云提供灵活的存储和 CDN 服务,适合对成本敏感、追求快速部署和开发的团队。

3 账号注册与准备

点击跳转七牛云免费云存储 开通七牛开发者帐号

注册完之后,直接登录七牛开发者后台下面几步要在页面上操作:

3.1 创建 ak 和 sk

进入到密钥管理处,创建 ak 和 sk

3.2 创建 bucket

接着进入到对象存储界面

在上方创建空间管理处新建一个空间,这个空间名字后面会用到,我们叫它(qiniu_bucket_name)

3.3 获取 qiniu_domain

创建完 bucket 之后,点击 bucket 查看详细信息中有一个外链域名,叫它(qiniu_domain)

3.4 获取七牛云的存储区域域名

在创建空间的地方,可以看到存储的区域,对应的 ID 到这里
区域 Region ID,记住这个 ID 对应的域名比如 http(s)://up-z0.qiniup.com,叫它 (qiniuZone)

上面我们获取了 ak、sk、bucket、qiniu_bucket_name、qiniu_domain 、qiniuZone 这五个值,这些配置后面会用到,我会以一个代码 snippets 来演示,具体用到 Node.js 作为服务端,Vue 作为前端来简单举例一下上传一个图片到七牛云 oss 上的流程。

接下来就是我们写代码来演示一下基本流程:

4 下载七牛云 SDK

这里选择 Node.js SDK

安装

1
npm install qiniu

4.1 鉴权

Node.js SDK 的所有功能,都需要合法的授权。授权凭证的签算需要七牛账号下的一对有效的 Access Key 和 Secret Key

4.2 文件上传业务流程

主要几个过程

  • 上传

客户端在上传资源到七牛云存储之前要先从业务服务器获取一个有效的上传凭证,因此需要先后和两个服务端打交道。

如果有设置回调,则上传完成时七牛云存储会自动发起回调到指定的业务服务器。

  • 下载

公开资源不需要对应的下载凭证,客户端可以直接从七牛云存储下载对应资源。私有资源需要对应的下载凭证,因此必须先和业务服务器打交道。

按照实际的使用场景,客户端对于内容的展示非常类似一个动态网页的生成过程,因此无论该页面内容是公开还是私有,均需要从业务服务器获取展示该页面的动态布局信息。所以通常显示过程也是需要先后和业务服务器及七牛云存储服务打交道。

  • 资源管理

为了防止安全漏洞,资源管理操作应该只在业务服务器端进行。如果允许客户端进行资源管理,即使将管理凭证的生成动作放到业务服务器端进行,仍然很容易被第三方截获请求全文,从而导致重放攻击的风险。

5 业务服务器端(NodeJS)

服务端 SDK 在上传方面主要提供两种功能:
一种是生成客户端上传所需要的上传凭证,另外一种是直接上传文件到云端

5.1 获取上传凭证 (uploadToken)

客户端上传前需要先从服务端获取上传凭证,并在上传资源时将上传凭证作为请求内容的一部分。不带凭证或带非法凭证的请求将返回 HTTP 错误码 401,代表认证失败。

所以需要构造上传策略:

示例:

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
import * as qiniu from 'qiniu';

// api/getQiniuToken
async getQiniuTokenAction() {
const access_key = 'qiniu_access_key'
const secret_key = 'qiniu_secret_key'
const bucket = 'qiniu_bucket_name'
const domain = 'qiniu_domain'
const mac = new qiniu.auth.digest.Mac(access_key, secret_key);
const currentTime = Number(new Date().getTime() / 1000) + 600;
const key = uuid(32);
//如果需要覆盖上传
// const keyToOverwrite = 'example.png'

const options = {
scope: bucket, // 如果需要覆盖上传凭证,scope: bucket + ":" + keyToOverwrite
deadline: currentTime,
saveKey: key,
expires: 7200 // 单位秒,默认一小时
};
const putPolicy = new qiniu.rs.PutPolicy(options);
const uploadToken = putPolicy.uploadToken(mac);
const info = {
token: uploadToken,
url: domain,
};
// console.log('qiniu_key', access_key, secret_key, bucket, domain);
// console.log(payload, data);
return info;
}

5.2 生成图片外链

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
36
37
38
39
40
41
42
43
//api/uploadHttpsImage
async uploadHttpsImageAction(payload) {
const { url } = payload;
const access_key = 'qiniu_access_key'
const secret_key = 'qiniu_secret_key'
const bucket = 'qiniu_bucket_name'
const domain = 'qiniu_domain'
const mac = new qiniu.auth.digest.Mac(access_key, secret_key);
let config: any = new qiniu.conf.Config();
const bucketManager = new qiniu.rs.BucketManager(mac, config);
const key = uuid(32);
// 空间对应的机房
config.zone = qiniu.zone.Zone_z0;
// 公开空间访问链接
const uploadQiniu = async () => {
return new Promise((resolve, reject) => {
try {
bucketManager.fetch(
url,
bucket,
key,
function (err, respBody, respInfo) {
if (err) {
console.log('err', err);
//throw err;
} else {
if (respInfo.statusCode == 200) {
resolve(respBody.key);
} else {
console.log(respInfo);
}
}
}
);
} catch (e) {
return resolve(null);
}
});
};
const httpsUrl = await uploadQiniu();
let lastUrl = domain + httpsUrl;
return lastUrl;
}

6 前端上传图片到业务服务器

这里为了简单演示,就以简单表单方式上传,分片上传逻辑先不考虑,但原理其实都一样的。

在每次上传图片之前(beforeUpload)调用 getQiniuToken 接口, 获得 uploadToken

示例:

1
2
3
4
5
6
7
8
9
getQiniuToken() {
axios.post('api/getQiniuToken').then(response => {
let resInfo = response.data.data
// resInfo = {
// token: ''
// url: ''
// }
})
}

6.1 获取图片外链

默认情况下,文件上传到存储之后,在没有设置 returnBody 或者回调相关的参数情况下,存储返回给上传端的回复格式为 hash 和 key。

最后上传成功后,根据 res 中返回的 key ,将 qiniu_domian+key 作为拼接字符串 url,

示例:

1
2
3
4
5
6
7
const handleUploadListSuccess (res) => {
const pic_url = url + res.key
axios.post('api/uploadHttpsImage', { url: pic_url}).then(response => {
let lastUrl = response.data.data
console.log(lastUrl)
})
}

6.2 Upload 组件

示例:

1
2
3
4
5
6
7
8
9
10
<el-upload
class="upload-demo"
name="file"
:action="qiniuZone"
:on-success="handleUploadBannerSuccess"
:data="picData"
:before-upload="getQiniuToken"
>
<el-button size="small" type="primary">点击上传</el-button>
</el-upload>

调用 qiniu SDK 完成资源内容上传 ,执行业务流程并返回得到最终的外链 url

最后,不出意外的话,前端就获得了 lastUrl 后就可以展示图片了。

七牛云最近年底搞活动,「新年大促」新年上云新优惠,新老客同享好价,对象存储低至 0.06 元/GB/月。
qiniu

立即了解更多

作者

Jimmy

发布于

2024-01-14

更新于

2024-03-05

许可协议

评论