AWS

亚马逊S3服务简单介绍

最近在做后端的开发,需要一些二进制数据保存在服务器云端。团队决定调查 AWS 的 S3 服务是否满足需求,所以就做了一些调查工作。不过也遇到很多坑的地方。所以记录下来,防止以后再遇到。

# 基本需求

需要云服务有稳定性保证,并且可以批量上传文件。可以设置上传和下载链接的有效期。

# AWS 试用

AWS 提供免费试用,但是注册的时候需要填写信用卡信息。确实有点不安,万一不小心被收费了就不好了。

# 生成上传凭证

我使用的是 AWS 的 JavaScript SDK。使用createPresignedPost API 可以创建用于上传的凭证。这个凭证是根据用户的 AccessId,AccessKey 和 Policy 策略等计算生成的,并没有和 AWS 服务器直接进行交互。所以不用担心这个接口和 AWS 直接的流量费用问题。

var params = {
  Bucket: 'bucket',
  Conditions: [['starts-with', '$key', 'path/to/uploads/']]
};
s3.createPresignedPost(params, function (err, data) {
  if (err) {
    console.error('Presigning post data encountered an error', err);
  } else {
    data.Fields.key = 'path/to/uploads/${filename}';
    console.log('The post data is', data);
  }
});
1
2
3
4
5
6
7
8
9
10
11
12

官方提供的例子中,可以使用starts-with的方式来指定上传文件的 key 必须是以什么开头的,这样就可以指定上传的文件夹。很多文件也可以使用这一个上传凭证来完成上传。

# 上传 Policy 构造

AWS 提供了一个详细文档说明如何构造合法的 Policy:Creating a POST Policy。例如常见的需求就是在上传的时候添加 meta 信息声明文件的格式或者 MD5 值。 Policy 的 Conditions 数组里面可以添加["starts-with", "$x-amz-meta-md5checksum", ""]。最后一个参数为空字符串代表可以上传任何数值。

# 构造 POST 表单

AWS 也有文档说明了如何构造一个上传的表单。这个表单中最重要的是一句注释:The elements after this will be ignored。在 file 字段之后的所有信息都会被忽略掉,我测试的时候一直把x-amz-meta-md5checksum字段放在 file 字段之后导致上传一直报错。直到 Stack Overflow 上面有人解释了才恍然大悟。

# 构造下载链接

我们使用getSignedUrl API 来生成下载链接,下载链接也是根据自己的 AccessId 和 AccessKey 生成链接的凭证,也没有和 AWS 服务器直接进行交互。当请求文件的时候,AWS 再计算凭证是否有效。所以后端无需和 AWS 交互就可以返回客户端有效的 AWS 下载链接。针对需要返回实际文件的 API 接口,可以采用返回 302 的跳转链接来完成需求。示例代码如下:

var params = { Bucket: 'bucket', Key: 'key' };
var url = s3.getSignedUrl('getObject', params);
console.log('The URL is', url);
1
2
3

可能有人会问,这个 API 也可以用来上传啊。但是这个 API 接口必须指定 key 值,这样我们就需要为每个文件来生成一个独立的上传 URL。这样太麻烦了。

# 总结

我们使用 pre-sign 的方式来生成 URL 主要是为了对客户端透明。虽然我们可以设置最小权限的 IAM User 给客户端,但是客户端很容易被逆向拿到敏感数据。这样难免会有风险,所以生成一个单纯的 URL 供客户端使用一定程度上保证了安全性也减少了客户端的复杂性。毕竟我也不想引入一个 AWS 的 SDK 进来。