分片上传(断点续传)
最后更新于:2022-04-01 00:53:56
分片上传功能支持将一个文件切割为一系列特定大小的小数据片,分别将这些小数据片分别上传到服务端,全部上传完后再在服务端将这些小数据片合并成为一个资源。[上传模型](http://developer.qiniu.com/docs/v6/api/overview/up/upload-models.html "上传模型")中对分片上传的特点进行了完整的阐述。
## 关键概念
分片上传引入了两个概念:**块**(block)和**片**(chunk)。每个**块**由一到多个**片**组成,而一个资源则由一到多个**块**组成。他们之间的关系可以用下图表述:
![资源、块、片的关系](http://developer.qiniu.com/docs/v6/api/overview/up/img/chunk-concept.png "资源、块、片的关系")
**块**是服务端的永久数据存储单位,**片**则只在分片上传过程中作为临时存储的单位。服务端会以约一个月为单位周期性的清除上传后未被合并为块的数据片。
## 基本流程
与分片上传相关的API有这几个:[创建块(mkblk)](http://developer.qiniu.com/docs/v6/api/reference/up/mkblk.html)、[上传片(bput)](http://developer.qiniu.com/docs/v6/api/reference/up/bput.html)、[创建资源(mkfile)](http://developer.qiniu.com/docs/v6/api/reference/up/mkfile.html)。一个完整的分片上传流程可用下图表示:
![分片上传流程](http://developer.qiniu.com/docs/v6/api/overview/up/img/chunked-upload-workflow.png)
其中的关键要点如下:
1. 将待上传的文件按预定义的4MB块大小切分为若干个块。如果这个文件小于4MB,当然也就只有一个块;
2. 将每个块再按预定义的片大小切分为若干个片,先在服务端创建一个相应块(通过调用[mkblk](http://developer.qiniu.com/docs/v6/api/reference/up/mkblk.html),并带上第一个片的内容),然后再循环将所有剩下的片全部上传(通过调用[bput](http://developer.qiniu.com/docs/v6/api/reference/up/bput.html),从而完成一个块的上传);
3. 在所有块上传完成后,通过调用[mkfile](http://developer.qiniu.com/docs/v6/api/reference/up/mkfile.html)将这些上传完成的块信息再严格的按顺序组装出一个逻辑资源的元信息,从而完成整个资源的分片上传过程。
如要更准确的理解这个基本流程,可以通过阅读SDK源代码。所有SDK的源代码都公开托管在[Github](http://github.com/qiniu)上。
## 并发上传
由于之前介绍的片上传过程中的Context机制,每个块内部只能按顺序逐一上传该块所切分好的片。而每个块之间相互独立,因此若干个块可以同时进行传输而不会相互干扰,因此我们可以利用这个特征实现并发上传特性。
每个文件对应的最大理论并发上传数量也即该文件可划分的块数量。当然这个理论数量也受到很多其他因素的制约,比如像iOS限定了每个APP最多只能开4个并发HTTP连接,也即在iOS上,无论有多少个块,最大的并发上传数量不可能超过4个。并不是并发数量越大上传速度就会越快。因此在实际开发中,通常会使用线程池(Thread Pool)技术来控制并发数量。
## 断点续传
虽然片的存在周期并非永久,但已足以实现断点续传机制。
每成功上传一个片,客户端都会收到服务端返回一个代表当前已上传多少片的进度信息,我们称之为Context。上传下一个片时应提供前一个片上传成功后返回的Context。因此,这个Context可以认为是片传输进度的一个标记。
如果上传过程中,服务端发现一个块已经被片数据装满,那么最后一个片上传成功后返回的Context将是一个特殊的值`EOB`,告诉客户端不要再往这个块附加更多的片。
如果客户端在每次收到Context信息时都将其持久化到本地,即使客户端程序意外崩溃或正常重启,都可以在启动时读取上一次上传成功的片对应的Context,从而接着继续传输剩余片。这个效果我们称之为断点续传。
断点续传功能在上传一个需要较长时间比如一天时间才能上传完毕的大文件时尤其有价值,毕竟我们很难保证这段很长的时间内客户端都不会被关闭,且网络也一直处于连接状态。当前主流的移动平台(iOS、Android、Windows Phone 8)都有监测非活动应用并自动将其关闭的功能,这意味着在移动平台上我们要上传一个大文件时更容易遇到中途程序突然被关闭的情况,断点续传也就更有价值。
支持断点续传功能之后,在客户端很自然可以支持一个新功能:暂停或恢复某个文传的上传过程。
## 上传后续动作
我们曾在[上传模型](http://developer.qiniu.com/docs/v6/api/overview/up/upload-models.html "上传模型")中提过,在上传时开发者可以指定上传完成后服务端的后续动作,比如回调、自定义返回内容、303重定向等。可设置的后续动作与[表单上传](http://developer.qiniu.com/docs/v6/api/overview/up/form-upload.html "表单上传")中完全一致。
这里需要明确的是,虽然后续动作在生成[上传凭证](http://developer.qiniu.com/docs/v6/api/reference/security/upload-token.html "上传凭证")时已经指定,但这些后续动作只在服务端处理完mkfile请求后才会发生,而且也只有mkfile请求的内容可以包含[变量](http://developer.qiniu.com/docs/v6/api/overview/up/response/vars.html "变量")。
## 在线示例
[在线断点继上传示例](http://jsfiddle.net/gh/get/extjs/4.2/icattlecoder/jsfiddle/tree/master/resumbleupload)