神的尾巴

全栈工程师、独立开发者

0%

阿里云 oss 前端直传

传统 OSS 上传方案,需要先从客户端上传到 Web 服务器,再从 Web 服务器上传到 OSS 服务器,文件经过中转导致消耗了流量和时间,另外如果客户端并发上传,对 Web 服务器带宽和性能都是不小的压力。

但是如果直接使用前端签名上传的话,则会有安全问题。

因此就有了服务端签名后直传方案。

官方文档:https://help.aliyun.com/document_detail/31926.html

如果需要获取上传回调,进行特殊操作,可以查看 服务端签名直传并设置上传回调

服务端签名前端直传方案流程如下:

服务端签名

这里使用 nodejs 作为示例。有官方的 SDK,省的我们对接阿里云 HTTP 接口造轮子。

安装 SDK

我使用的 sdk 是 ali-oss:https://github.com/ali-sdk/ali-oss

吐槽下,阿里 sdk 命名不统一,@alicloud/xxxali_sdk/xxx

执行 npm install 安装 sdk。

1
npm install ali-oss --save

构建 Post Policy,获取上传签名

这里可以参照下官方 SDK 的 demo:https://github.com/ali-sdk/ali-oss/blob/master/example/server/postObject.js

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
const config = {
accessKeyId: '<accessKeyId>',
accessKeySecret: '<accessKeySecret>',
// 上传 bucket endpoint
endpoint: '<bucket endpoint>'
bucket: '<bucket>'
}

// 从初始化 OSS
const client = new OSS(config)

// 构建 policy 对象
const date = new Date();
// 获取过期时间为1天,这里可以根据情况,自己设置过期时间
date.setDate(date.getDate() + 1)
const policy = {
expiration: date.toISOString(), // 请求有效期
conditions: [
['content-length-range', 0, 1048576000], // 设置上传文件的大小限制
{ bucket: client.options.bucket } // 限制可上传的bucket(可选)
]
}

// 获取上传签名
const formData = await client.calculatePostSignature(policy)

// 返回给前端
return {
formData,
url: config.endpoint
}

Post Policy 的详细介绍:https://help.aliyun.com/document_detail/31988.html

必须包含 expiration 和 conditions。

Expiration: 指定过期时间
Conditions: 是一个列表,用来指定 Post 请求的表单域合法值。

Conditions 使用方式见下图:

前端使用签名直传

这里以支付宝小程序为例,其他平台类似。

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
// 假设服务端获取上传签名接口返回值存储到 apiRet 变量

/**
* apiRet: {
* url: 'oss上传url',
* formData: {
* // ... 上传所需参数、签名
* }
* }
*/

alipay.uploadFile({
url: apiRet.url,
formData: {
// 存储到 bucket 的路径
key: "<上传指定的key>",
// 设置成功返回的状态值 200
success_action_status: 200,
// 解构 接口返回 formData
...apiRet.formData,
},
// 文件名一定要是 file
name: "file",
// 支付宝小程序需要指定
fileType: "image",
filePath: "<本地文件路径,可以通过选择相册获取>",
});

需要注意的点

有一个安全问题需要注意,如果黑客获取签名后,可以直接伪造请求,覆盖之前用户上传的图片,如果用户之前上传的是自己的付款码,可以直接修改为黑客的付款码。

解决方案如下:

生成签名时,conditions 指定 key 前缀(可以使用基于时间戳的 uuid),前端上传时,使用该前缀 key + 前端随机串上传。

觉得对你有帮助的话,请我喝杯咖啡吧~.