实现 RESTful 大文件上传的正确方法

2022-09-01 02:39:04

我已经制作REST API一段时间了,我仍然纠结于一个案例 - 大文件上传。我读过其他一些API,如Google Drive,Twitter和其他文献,我有两个想法,但我不确定它们中的任何一个是否“正确”。正如在适当的时候,我的意思是它在某种程度上是标准化的,不需要太多的客户端逻辑(因为其他各方将实现该客户端),或者更好的是,它可以很容易地用cURL调用。计划是在Java中实现它,最好是Play Framework。

显然,我需要一些文件分区和服务器端缓冲机制,因为文件很大。

因此,我得到的第一个解决方案是分段上传()。我是这样理解的,我以前也像这样实现过它,但是对我来说,在客户端实际模拟表单总是很奇怪,特别是因为客户端必须设置文件键名称,而根据我的经验,这是客户端有点忘记或不理解的东西。另外,如何规定块大小/部分大小?是什么阻止客户端将整个文件放在一个块中?multipart/form-data

解决方案二,至少我理解的,但没有找到实际的实现实现是“常规”POST请求可以工作。内容应分块,数据在服务器端缓冲。但是,我不确定这是否是一个正确的理解。数据实际上是如何分块的,上传是跨越多个HTTP请求还是在TCP级别分块?什么是?Content-Type

底线,这两者(或其他任何东西?)应该是一种客户端友好,广泛可理解的实现REST API以进行文件上传的方式吗?


答案 1

我建议您看一下 Amazon S3 Rest API 的分段文件上传解决方案。可在此处找到文档。

总结一下亚马逊使用的过程:

  1. 客户端发送请求以启动分段上传,API 使用上传 ID 进行响应

  2. 客户端上传每个文件块,其中包含部分编号(以保持文件的顺序),部分的大小,部分的md5哈希和上传ID;这些请求中的每一个都是一个单独的 HTTP 请求。API 通过检查收到的 md5 哈希块与客户端提供的 md5 哈希来验证块,并且块的大小与客户端提供的大小匹配。API 使用块的标记(唯一 ID)进行响应。如果跨多个位置部署 API,则需要考虑如何存储块,并在以后以位置透明的方式访问它们。

  3. 客户端发出完成上传的请求,其中包含从API收到的每个区块编号和关联的区块标记(唯一ID)的列表。API 验证没有丢失的块,以及块编号是否与正确的块标记匹配,然后组装文件或返回错误响应。

Amazon 还提供了中止上传的方法,并列出了与上传关联的区块。您可能还需要考虑上传请求的超时,如果上传未在一定时间内完成,则块将被销毁。

在控制客户端上传的块大小方面,您将无法对客户端决定如何拆分上传进行太多控制。您可以考虑为上传配置最大区块大小,并为包含大于最大大小的区块的请求提供错误响应。

我发现该过程非常适合在REST API中处理大型文件上传,并有助于处理与文件上传相关的许多边缘情况。不幸的是,我还没有找到一个库,可以很容易地在任何语言中实现它,所以你几乎必须自己编写所有的逻辑。


答案 2

https://tus.io/ 是可恢复协议,有助于块上传并在超时后恢复上传。这是一个开源实现,并且已经以不同的语言实现了各种客户端和服务器。