Amazon S3 是互联网存储解决方案,能让所有开发人员访问同一个具备可扩展性、可靠性、安全性和快速价廉的数据存储基础设施。Amazon S3 提供了一个简单 Web 服务接口,可用于随时在 互联网上的任何位置存储和检索任何数量的数据。开发人员可以利用 Amazon 提供的 REST API 接口,命令行接口或者支持不同语言的 SDK 访问 S3 服务.
同时 S3 对于上传功能的 API 提供也是非常丰富的,与此同时,很多客户对于 S3 的断点续传也有了很深入的需求,本篇博客将会介绍如何使用 S3 的 Javascript SDK 来实现客户端浏览器到 S3 的断点续传功能.
安全考量
首先我们需要度量在浏览器客户端直连上传到 S3 这个场景下的安全问题,我们是一定不能把我们的 AccessKey 暴露到客户端浏览器的,但是上传到 S3 的 API 一定要提供 AccessKey 和 SecretKey,因此这里我们将会利用生成临时的 AccessKey 和 SecretKey(结合有效期)的方式来保证客户端的上传,这里介绍一篇关于利用 TVM (Token Vending Machine)来生成临时 Key 并上传 S3 的文章,本文主要探讨关于 S3 的分片上传和断点续传的知识点.
Javascript SDK 和 S3 API 简介
从整体编程语言架构的层面上来讲,AWS 的各个语言的 SDK 都主要划分为上层和下层的 API, 上层 API 主要是针对一些用户必要的功能利用下层 API 所作的一层封装,掌握了这个原则之后我们就可以合理的利用 AWS 的上层 API 看能否实现自身的需求.
Javascript SDK 文档总结
在掌握 SDK 之前,我们应该先对 SDK 的文档和大致的结构有一个了解,这样才能方便我们更好的使用 SDK, 下面列出了 SDK 的官网入门连接和 API 参考文档.
API 参考文档: http://docs.aws.amazon.com/AWSJavaScriptSDK/latest/index.html
S3 API 参考文档: http://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/S3.html
构建 SDK 中的 S3 对象
首先,AWS 的 SDK 都是先需要利用 Credentials 来构建对象的,这里我们构建 S3 的对象也是如此,但是请注意一定不能将自己的 Key 暴露在客户端或者提交到代码中,应该使用 TVM 获取了 Key 之后再利用 AWS.Credentials 对象来构建 S3 的对象.
在构建 S3 对象时,也需要同时指定 AWS 的 Region.
利用上层 Javascript API 构建简单的分片断点续传功能
接下来,我们一步一步的来创建上层 API 构建断点续传的实践.
1. 创建工程
这里我们以 node.js 平台的 express 来提供简单的静态服务. 本文不会涉及如何安装 node.js,关于安装指南,可以参考官网 nodejs.org 首先利用 npm 包管理器安装 express 模版生成器:
npm install express-generator -g
完成后我们利用命令行生成项目:
mkdir s3upload
express --view=ejs
这里的--view=ejs
主要指定 ejs 作为 express 的 html 模版引擎,方便我们的测试. 创建好之后的工程结构如下图:
编写页面 UI
``
这里我们通过引入<script src="https://sdk.amazonaws.com/js/aws-sdk-2.45.0.min.js"></script>
来在浏览器端倒入 AWS SDK, 并且我们创建了一个 id 为 progress 的 label 来监控进度. 最后我们引入了/javascript/index.js
来编写我们页面的业务逻辑.
分片上传控制
接下来我们在 public/javascript 文件夹中创建 index.js
简单的两个静态文件就能够完成分片上传的功能了.
启动项目
由于 Express 已经建立好模版,只需要在控制台输入 npm start 就能够在 3000 端口监听服务,通过访问 http://localhost:3000 就能够测试分片上传的功能了.
完整的项目代码可以在 Github 上访问.
设置 CORS
由于 SDK 通过 Ajax 提交数据,需要在 S3 桶策略中配置跨域提交的 CORS. 示例中的*建议在生产环境中改成自己的域名.
S3 上层 API 说明
以上实践为大家简单介绍了如何使用 S3 点上层 API 自动完成分片上传的功能,并且通过事件监控的方式来了解上传的进度,这里主要有以下几点需要注意.
1). 上传 api 需要指定 Bucket: ‘testupload’, Key: file.name 让 SDK 识别到桶和文件的 Key 名称.
2). 由于是上层 API, 因此上传程序将会实施自动分片,由于 S3 的最小分片是 5M,所以当文件大于 5M 时此上传程序才会进行自动分片,并且每隔 5M 为一个切片进行上传工作.
3). SDK 使用 AJAX 方式提交自动分片的文件,因此需要设置 S3 的跨域提交配置 CORSRule.
4). 在整个过程中,不要在客户端暴露 AccessKey 和 Secret,利用TVM (Token Vending Machine)一文来安全获取临时 Token.
通过底层 API 来编写实现更多分片上传的功能.
S3 的分片上传主要的原理是通过初始化一次上传的 uploadId, 然后在主动取消或者完成前会一直沿用这个 uploadId,如果用户使用这个 uploadId 持续上传分片则会一直保持该文件的上传,最后通过一个 complete 的操作来结束上传,并且会合并所有分片成为一个文件. 通过上述原理,我们的底层 API 主要会调用以下来实现自定义的分片上传:
1). 首先调用 createMultipartUpload
2). 在返回了 uploadId 之后,将文件切片后利用 uploadPart API 指定在同一个 uploadId 下从第几段开始上传.
3). 最后调用 completeMultipartUpload 结束上传,同时请求成功后 S3 将会自动合并所有分片成为一个文件.
关于各个 API 的详细参数,请参考官方文档.
最后,我们需要注意的是,在整个客户端上传的过程中,难免会有分片并没有全部上传完毕,或者没有最终成功调用了 completeMultipartUpload 的孤儿分片存在,而且随着时间的推移,这些孤儿分片也会越来越多,并且这些没有被 S3 合并的分片,在 S3 的管理控制台中是不可见的,那么我们的最佳实践应该是怎样的呢? 首先我们可以使用 abortMultipartUpload 来取消分片,那么某一次上传没有完成合并的分片将会被清除, 这个可以结合 API 来配合使用.
其次,虽然 S3 控制台中并不会显示未上传完成的孤儿分片,但是我们可以通过 listMultipartUploads 和 listParts 来查看未完成的分片有哪些.
最后,也是最自动的方法是我们可以使用 S3 的桶生命周期 Policy 来设置自动清除和保留未完成合并的孤儿分片的时间周期,让我们并不需要花精力来处理这些异常的情况.
总结
S3 作为轻量简易高可用的存储,结合 AWS 的 SDK,我们在通过临时证书的交互后可以轻易的实现安全的浏览器客户端直接分片断点续传到 S3 的功能,无论是借助于上层的 S3 上传 API 还是利用底层的 createMultipartUpload 实现方式,Javascript SDK 都能够在各个层面给到开发人员灵活轻便的实现这些逻辑,从而让开发人员更专注在自身业务的开发工作中.
作者介绍
李磊
AWS 解决方案架构师,负责基于 AWS 的云计算方案的架构设计,同时致力于 AWS 云服务在国内和全球的应用和推广。在大规模并发后台架构,电商系统,社交网络平台、互联网领域应用,DevOps 以及 Serverless 无服务器架构等领域有着广泛的设计与实践经验。在加入 AWS 之前超过十年的开发和架构设计经验, 带领团队攻克各种技术挑战,总是希望站在技术的最前沿。
本文转载自 AWS 技术博客。
原文链接:
https://amazonaws-china.com/cn/blogs/china/s3-multipul-upload-practice/
评论