参考文献

前端控件

WebUploader

秒传

  • 即通过计算文件的MD5,若文件MD5相同则不需要上传,从而实现"秒传"操作.

秒传核心逻辑

  • 利用Redis的set方法存放文件上传状态,其中key为文件上传的md5,value为是否上传完成的标志位,
  • 当标志位true为上传已经完成,此时如果有相同文件上传,则进入秒传逻辑.如果标志位为false,则说明还没上传完成,此时需要在调用set的方法,保存块号文件记录的路径,其中key为上传文件md5加一个固定前缀,value为块号文件记录路径
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
@Slf4j
@RestController
@RequestMapping("/upload")
public class UploadController {
private static final Map<String, String> CACHE = new HashMap<>(16);
private static final String PREFIX = "pass_upload_";
private static final String SUFFIX = ".temp";
private static final String EMPTY = "";

@RequestMapping("/pass")
public String passUpload(@RequestParam("file") MultipartFile file) {
try {
final String digest = SecureUtil.md5(file.getInputStream());
// 使用Map模拟Redis
if (CACHE.containsKey(digest)) {
log.info("重复文件");
return CACHE.get(digest);
} else {
log.info("新文件");
final File tempFile = File.createTempFile(PREFIX, SUFFIX);
file.transferTo(tempFile);
final String absolutePath = tempFile.getAbsolutePath();
CACHE.put(digest, absolutePath);
return absolutePath;
}
} catch (IOException e) {
e.printStackTrace();
}
return EMPTY;
}
}

分片上传

  • 分片上传,就是将所要上传的文件,按照一定的大小,将整个文件分隔成多个数据块(我们称之为Part)来进行分别上传,上传完之后再由服务端对所有上传的文件进行汇总整合成原始的文件.
img

流程

  1. 客户端调用对象存储发起分片上传.
  2. 数据存储返回一个uploadID,唯一标识此次上传.
  3. 客户端将大文件拆分成小文件并开始上传.假设文件大小为 1.6GB,客户端将其分为 8 个部分,因此每个部分大小为 200 MB.客户端将第一部分连同在步骤 2 中收到的 uploadID 一起上传到数据存储.
  4. 当上传某个部分时,数据存储会返回一个 ETag,它本质上是该部分的 md5 校验和.它用于验证分段上传.
  5. 所有分片上传完毕后,客户端发送完整的分片上传请求,请求中包含uploadID、分片编号和ETag.
  6. 数据存储根据部件号将对象从其部件中重新组装.由于对象非常大,因此此过程可能需要几分钟.重组完成后,向客户端返回成功消息.

使用场景

  • 网络环境不好:当出现上传失败的时候,可以对失败的Part进行独立的重试,而不需要重新上传其他的Part.
  • 断点续传:中途暂停之后,可以从上次上传完成的Part的位置继续上传.
  • 加速上传:要上传到OSS的本地文件很大的时候,可以并行上传多个Part以加快上传.

  • 流式上传:可以在需要上传的文件大小还不确定的情况下开始上传.这种场景在视频监控等行业应用中比较常见.

  • 文件较大:一般文件比较大时,默认情况下一般都会采用分片上传.

断点续传

  • 断点续传是在下载或上传时,将下载或上传任务(一个文件或一个压缩包)人为的划分为几个部分,每一个部分采用一个线程进行上传或下载,如果碰到网络故障,可以从已经上传或下载的部分开始继续上传或者下载未完成的部分,而没有必要从头开始上传或者下载.本文的断点续传主要是针对断点上传场景.
使用场景
  • 断点续传可以看成是分片上传的一个衍生,因此可以使用分片上传的场景,都可以使用断点续传.
断点续传的核心逻辑
  • 在分片上传的过程中,如果因为系统崩溃或者网络中断等异常因素导致上传中断,这时候客户端需要记录上传的进度.在之后支持再次上传时,可以继续从上次上传中断的地方进行继续上传.
  • 为了避免客户端在上传之后的进度数据被删除而导致重新开始从头上传的问题,服务端也可以提供相应的接口便于客户端对已经上传的分片数据进行查询,从而使客户端知道已经上传的分片数据,从而从下一个分片数据开始继续上传

示例