前端大文件切片上传

更新时间:2023-02-22 15:57:53标签:web前端

浏览器端

文件切片和MD5值计算

1import SparkMD5 from 'spark-md5';
2import { Observable } from 'rxjs';
3
4export interface SlicedFile {
5 md5: string;
6 chunks: Blob[];
7}
8
9export function fileSlice(file: File, sliceSize: number/* byte */) {
10 return new Observable<[number, SlicedFile | null]>(subscriber => {
11 const spark = new SparkMD5.ArrayBuffer();
12 const maxCount = Math.ceil(file.size / sliceSize);
13 const chunks: Blob[] = [];
14 const fileReader = new FileReader();
15 fileReader.onload = (e) => {
16 spark.append(e.target!.result as ArrayBuffer);
17 loadNext();
18 };
19 fileReader.onerror = (err) => {
20 subscriber.error(err);
21 };
22 const loadNext = () => {
23 if (chunks.length < maxCount) {
24 const start = chunks.length * sliceSize;
25 subscriber.next([Math.min(1, start / file.size), null]);
26 const end = Math.min(start + sliceSize, file.size);
27 const blob = file.slice(start, end);
28 fileReader.readAsArrayBuffer(blob);
29 chunks.push(blob);
30 } else {
31 subscriber.next([1, { md5: spark.end(), chunks }]);
32 subscriber.complete();
33 }
34 };
35 loadNext();
36 return {
37 unsubscribe() {
38 fileReader.abort();
39 },
40 };
41 });
42}

上传过程

1/**
2 * @type {SlicedFile}
3 */
4var slicedFile;
5(async () => {
6 for (let i = 0; i < slicedFile.chunks.length; i += 1) {
7 const formData = new FormData();
8 formData.append('file', slicedFile.chunks[i]);
9 await fetch(`/upload?md5=${slicedFile.md5}&index=${i}`, {
10 body: formData
11 });
12 }
13})();

暂停上传

前端中断顺序上传过程的行为即为暂停,上传进度为最后一次上传成功的切片

继续上传

  1. 服务端需要提供一个接口,接收参数为md5,前端通过此接口查询该md5对应的文件是否处于暂停中的状态;
  2. 如果查询到该md5对应的文件处于暂停状态,则返回前端当前暂停处于第几个切片;
  3. 前端从该切片开始,继续上传任务;

文件秒传

  1. 前端根据md5值,通过后端接口查询该md5值对应文件的存储状态;
  2. 如果查询到该文件已经存在于文件服务器,则直接展示文件链接(根据业务需求);

服务端

建立一个临时文件夹,名称为用户上传文件的md5

例如:

  • 518798f72fea56abae47a08e0b363021(文件夹名,md5值)
    • 0(第一个切片)
    • 1(第二个切片)
    • 2(第三个切片)
    • 3(第四个切片)
    • ...

用户暂停上传

  1. 保留该上传任务的临时文件夹及所有已完成上传的切片文件;
  2. 可以在数据库记录当前文件的上传状态(比如暂停中),uniqueID取md5;

用户继续上传

  1. 查询该md5对应的文件状态是否为暂停中;
  2. 继续接收用户上传的切片;

用户上传成功

  1. 所有切片完成上传后,合并所有切片,并校验md5值;
  2. 存储到服务器,并更新数据库状态;

文件秒传

  1. 数据库保存某个文件的md5及该文件的存储状态(比如上传成功);
  2. 提供md5查询接口,前端根据md5查询某个文件是否存在,若存在则返回文件链接(根据业务需求);