一 TUS 文件上传流程图
基于上面的流程图这里简单描述一下并讲讲其中一些注意的地方。
客户端首先向服务端发送options请求。获取服务端的配置,
比如服务端支持的tus版本,或者支持的tus扩展。
如果服务端支持,客户端可以选择:
向服务端发起post请求创建文件副本
发送post请求的同时发送部分文件分片
直接发送head请求尝试恢复上传,如果失败则回退到post创建文件。
服务端返回文件的相关信息用于后续文件上传请求。
恢复上传: 根据服务端返回的响应头Upload-Offset从指定文件位置开始恢复上传
首次上传: 从文件开始位置上传。也就是0。
重复发起patch请求发送文件分片,根据服务端响应的Upload-Offset来确定下一分片位置。
如果它的值等于文件的大小,说明文件上传已经完成。
至此整个文件上传流程完成。
二 Tus 扩展
Tus还有许多扩展用于帮助开发者实现更多的功能。在上面的流程中已经用到了一些。
以下所有的扩展都需要服务端支持。
官方的方法是在options请求当中的响应中根据Tus-Extension响应头来分析具体服务端所接受的扩展。
下面的扩展会影响到上面请求流程中的很多地方,也会在下面介绍。(很多地方其实还是对官网的翻译,如果有兴趣的可以去官网继续学习更多的内容?)
Creation
在文件上传前在服务端创建文件信息
可以将文件的相关信息预先在存储在服务端,这样可以为后续文件分片上传做参照。
比如可以将文件唯一标识符md5先进行上传,服务端存储数据库,保存每一上传的分片。
前端可以把一些文件信息放在Upload-Metadata请求头中
服务端会返回Location告知前端文件的上传地址。
Creation-With-Upload
在服务端创建请求中添加文件分片内容
为了节省流量,在服务端允许的情况下,可以在向服务端创建请求的同时也将某一分片一同上传。
和Creation类似,也会返回Location头,同时会返回Upload-Offset设置下一分片的索引。
Expiration
临时文件的过期时间
服务端的存储空间毕竟有限,不可能无时限的将文件的分片保存在服务端的数据库中。
所以服务端可以设置分片的存储时间,并通过响应头Upload-Expires告知前端它的过期时间。
当超过服务端规定的时间之后,用户需要重新在服务端创建文件副本,重新上传。
当前端发送文件分片响应时,服务端会添加响应头Upload-Expires告知前端该分片过期时间,如果超过时间,服务端将会返回404,前端需要重新上传。
Checksum
分片大小检查
服务端可以对前端发送的文件分片进行校验。
在上传前获取服务端上传配置支持度信息时,前端可以根据Tus-Checksum-Algorithm字段知道服务端支持的加密算法。
有时无法一开始就做出相应的计算,并且在服务端支持的情况下,可以使用Trailer请求头在完成上传后再进行校验。
服务端可以在一开始options的Tus-Extension中添加Checksum-Trailer字段表示支持该功能。
比如对文件进行md5加密,需要对文件分片一一进行处理。
当上传校验失败时,服务端便会丢弃此分片,索引也不会发生改变。
上述例子中
服务端options响应中Tus-Checksum-Algorithm: md5,sha1,crc32展示了其支持的校验算法
前端patch请求Upload-Checksum: sha1 Kq5sNclPz7QV2+lfQIuc6R7oRu0=使用sha1算法。
服务端校验通过返回204
若失败,则返回以下状态码(400: 算法不支持,460: 校验和不匹配)
官网上介绍The Upload-Checksum request header contains information about the checksum of the current body payload. The header MUST consist of the name of the used checksum algorithm and the Base64 encoded checksum separated by a space.
大概说上面的Upload-Checksum头由sha1算法和由base64编码的校验和组成,但是我不是太能理解这个,不管是使用base64解码或者用sha1解码似乎都无法解码出Kq5sNclPz7QV2+lfQIuc6R7oRu0=,如果有懂的大佬的话可以给解释解释?。
Termination
文件删除
这个应该没什么好说的,就是向服务端请求删除文件信息。
Concatenation
并行上传
对于一个大文件,如果是一个个分片串行上传,可能还是有点慢。tus支持可以实行并行上传,可以针对同一个文件资源在服务端生成多个上传地址,这样就可以同时上传文件的不同分片。
当然这也需要服务端支持。
上述例子中
先是在开始时发送两个post请求并携带Upload-Concat: partial请求头,在服务端生成了两个上传地址https://tus.example.org/files/a和https://tus.example.org/files/b
接着就可以同时在两个地址上传同一个文件,以此来提高效率。
当上传完所有分片后,发送post请求并携带Upload-Concat: final;/files/a /files/b,格式为final;加上上一步中生成的上传地址,以空格分隔。服务端响应合成路径Location: https://tus.example.org/files/ab告知前端文件的地址。该顺序需要和post中返回的地址顺序一致,否则可能会导致服务端文件分片合并出错。
前端发送head请求,服务端接收到请求完成这个文件分片的合并。
就我个人看法,Tus协议提供的是一种思想,让我们在文件上传任务中出现的任何情况都能得到相应的应对方法,完美完成整个上传流程。
所在上面所介绍的扩展,不严谨的讲,我们可以用自己的方法来实现,它的作用就是能让两端能更好的理解当前的文件的上传情况。
我们不必太过于拘泥于相应的api,只需要能让两端更好,更容易的协作就好。
还有,在我使用前端tus的tus-js-client工具时,检查api介绍以及粗略查找了下源码,看到它似乎对于tus扩展只实现了Creation、Creation-With-Upload、Concatenation这几个扩展,如果想使用其他扩展可能需要自行实现。
不过其他几个扩展的重点在后端,这也可能是它没有实现的原因。(也可能是我没看懂?)
三 TUS 编程
server的基本接口
这里我们不提供params和query参数这些,我们只简单介绍下接口。
- POST “/”, 这是最开始的接口,返回一个不存在的url,也就是开始创建一个上传时在headers里返回一个url。
- HEAD “/:id”,其实这里的”/:id”就是获取的url,这是获取offset用的。
- PATCH “/:id”,这就是传输文件的核心接口,直到真正上传完毕,patch接口才会关闭
- GET “/:id”,顾名思义,这是读取文件或者就是下载作用。
- DELETE “/:id”,这就是删除文件的操作。
client的操作
其实有许多的headers是必备的,不过这里我们先不讨论这些,由于官网给的server和client都有demo,而且很多逻辑没有让我们自己实现,所以想清楚的了解请求参数这些的,必须去读源码了解一下。
客户端这边其实很简单,本地保存一个数据库或者其他什么可以储存键值对json文件的就行,对于要上传的文件,总能匹配创立一个唯一的md5的key,通过这个key在client本地找寻url,如果有表示之前创立过url和上传,那就可以续传;如果没有,表示这是第一次传输,需要POST请求道server去创立一个url。
有了url之后,就是Head-Patch的请求了,先head是为了获取offset,如果offset和filesize一样,表示传完了,如果offset < filesize,那么就可以续传,对这个url传输就行,传输开始就是offset之后的内容即可。
结束
参考文档
文件断点续传的协议-Tus 协议