大文件快速上传的方案,其实无非就是将 文件变小,也就是通过 压缩文件资源 或者 文件资源分块 后再上传。
具体来说,可以考虑以下几种方法:
-
分片上传(Chunked Upload):将大文件拆分成小的文件块(chunk),然后通过多个并行的请求依次上传这些文件块。服务器接收到每个文件块后进行存储,最后合并所有文件块以还原原始文件。这种方法可以降低单个请求的负载,并允许在网络中断或上传失败时可以从断点续传。
-
流式上传(Streaming Upload):客户端使用流方式逐步读取文件的内容,并将数据流通过 POST 请求发送给服务器。服务器端能够逐步接收并处理这些数据流,而无需等待完整的文件上传完成。这种方法适用于较大的文件,减少了内存占用和传输延迟。
-
使用专门的文件上传服务:有一些第三方服务可供使用,例如云存储服务(如 Amazon S3、Google Cloud Storage)、文件传输协议(如 FTP、SFTP)等。这些服务通常提供了高可靠性、可扩展性和安全性,并且针对大文件上传进行了优化。
-
压缩文件上传:如果可能,可以在客户端先对文件进行压缩,然后再进行上传。压缩后的文件大小更小,可以减少上传时间和网络带宽消耗。
-
并发上传:通过多个并行的请求同时上传文件的不同部分,以加快整个上传过程。这需要服务器端支持并发上传并正确处理分片或部分文件的合并。
-
断点续传:记录上传进度和状态,以便在网络中断或上传失败后能够从上次中断的位置继续上传。可以使用客户端或服务器端的断点续传机制来实现。
补充知识点
问题 1:谁负责资源分块?谁负责资源整合?
当然这个问题也很简单,肯定是前端负责分块,服务端负责整合.
问题 2:前端怎么对资源进行分块?
首先是选择上传的文件资源,接着就可以得到对应的文件对象 File,而 File.prototype.slice 方法可以实现资源的分块,当然也有人说是 Blob.prototype.slice 方法,因为 Blob.prototype.slice === File.prototype.slice
.
问题 3:服务端怎么知道什么时候要整合资源?如何保证资源整合的有序性?
由于前端会将资源分块,然后单独发送请求,也就是说,原来 1 个文件对应 1 个上传请求,现在可能会变成 1 个文件对应 n 个上传请求,所以前端可以基于 Promise.all 将这多个接口整合,上传完成在发送一个合并的请求,通知服务端进行合并。
合并时可通过 nodejs 中的读写流(readStream/writeStream),将所有切片的流通过管道(pipe)输入最终文件的流中。
在发送请求资源时,前端会定好每个文件对应的序号,并将当前分块、序号以及文件 hash 等信息一起发送给服务端,服务端在进行合并时,通过序号进行依次合并即可。
问题 4:如果某个分块的上传请求失败了,怎么办?
一旦服务端某个上传请求失败,会返回当前分块失败的信息,其中会包含文件名称、文件 hash、分块大小以及分块序号等,前端拿到这些信息后可以进行重传,同时考虑此时是否需要将 Promise.all 替换为 Promise.allSettled 更方便.