一、简化演示
分块上传、合并分块
前端将完整的视频文件分割成多份文件块,依次上传到后端,后端将其保存到文件系统。前端将文件块上传完毕后,发送合并请求,后端拿取文件块,合并后重新上传到文件系统。
断点续传
前端遍历文件块,每次上传之前,先询问文件块是否存在,只有不存在的情况下,才会上传。
秒传
前端分割视频文件前,先询问此视频是否已经存在,存在则不再上传,后端之间返回视频信息。前端看起来就像是被秒传了。
二、更详细的逻辑和细节问题
- 视频文件和文件块都通过文件本身计算
MD5值
作为唯一标志 - 文件系统使用
Minio
,只要提供buckerName
和path
就可以操作文件 - 后端合并文件块成功后会删除文件块,并以
MD5
值为id
存入数据库 Minio
存储文件块时,依据其md5
值计算path
,比如取前两个字符构建二级文件夹,文件名为md5
值,无后缀。所以只需要提供文件块的md5
值就可以操作文件块。Minio
存储完整视频文件时,依据其md5
值计算path
,同上,文件名为md5
值,携带.mp4
等后缀,所以只需要提供视频文件的md5
值就可以操作视频文件。
- 首先,前端计算视频文件的
MD5
值,记为fileMd5
,传递MD5值来询问后端此视频文件是否存在,后端查询数据库返回结果,如果存在,则前端触发”秒传”。 - 如果不存在,则将视频文件分割成文件块,循环上传,每次循环,首先计算文件块的
md5
值,传递md5值询问后端此文件块是否存在,后端根据md5
判断文件块是否存在,如果存在,前端跳过此文件块上传,直接标记为上传成功,如果不存在,则上传至后端,后端将其保存到minio
。这其实就是”分块上传,断点续传”。 - 最后所有分块文件都上传成功,前端发起合并请求,传递视频文件的
md5
值和所有文件块的md5
值到后端,后端进行文件块合并、文件块的删除、合并文件的上传,将信息存储在mysql
数据库,将执行结果告知前端。这就是”合并分块”
可能存在的隐患
一个视频文件的文件块没有全部上传完成就终止,此时文件块将一直保存在
minio
中,如果之后此视频再也没有发起过上传请求,那么这些文件块都是是一种垃圾。
可以写一个定时任务,遍历Minio
没有后缀的文件块,判断其创建时间距离当前是否足够久,是则删除。
三、代码示例
前端代码
1 | <template> |
1 | export const getMedia = (id: string | number): AxiosPromise<MediaVO> => { |
后端代码
1 | @RestController |
关于如何操作Minio等文件系统,不详细写明解释。只需要知道,给Minio提供文件本身、bucketName、path即可完成上传、下载、删除等操作。具体代码不同的包都不一样。
1 | @Service |