Skip to content

大文件http上传前端设计

1、前言

现有大文件上传只能上传一个且必须停留当前页面,在大文件过大时比较占用用户时间。且目前大文件http上传在流程处理上也比较粗糙。

2、设计目标

  • 用户上传大文件不会阻塞用户其他操作;
  • 实现暂停、继续功能;
  • 实现取消功能;
  • 实现上传进度条和速度功能;

3、 前置技术条件介绍;

  • 在JavaScript中,文件FIle对象是Blob对象的子类,Blob对象包含一个重要的方法slice通过这个方法,我们就可以对二进制文件进行拆分
  • 使用 FormData 格式进行上传, FormData 是 Ajax2.0 对象用以将数据编译成键值对,以便于 XMLHttpRequest 来发送数据。
  • Promise: Promise是一种用于异步编程的JavaScript对象,Promise通过链式调用的方式,能较好地处理异步任务执行回调等问题;

4、项目排期

4、总体设计

流程图

  1. 打开新tab并监听大文件列表是否出于视口;
  2. 发起创建大文件对象http,并保存副本到本地;
  3. 将大文件文件切片进行顺序上传;
  4. 前端携带是完成所有切片标识,后端合并完成所有切片;
  • 4.1 打开新标签页并创建大文件
    • 在大文件列表时在document对象上挂在挂载visibilitychange,每次大文件列表处于视窗可见时获取最新大文件列表;保证从其他视口每次看到的大文件列表都是最新的;
    • 点击列表页面创建大文件使用window.open(url,"_blank")打开新标签页;
    • 由于新标签页处于独立tab中则不会对用户其他操作造成操作阻塞;
  • 4.2 生成image对象
    • 在发起http请求并且后端成功创建image大文件对象后,前端将该条大文件信息记录为images对象数组,数组中每一条数据都对应一个大文件对象;数据结构如下;

流程图

  • 4.3 分片上传 分片上传主要流程如下
    • 创建切片,循环分解文件即可,每一片大小为10M且携带下标chunk;分片切割完成后更新images中对应的total_chunks 总分片数;
    • 同时上传任务数量控制,由于大规模任务上传受限于性能影响,大文件对象数组中设置上传限制,最大任务上传max_concurrent_tasks = 3 ,images 对象数据中uploading数量与max_concurrent_tasks 始终保持一致。设置上传队列tasks_queue,tasks_queue如果任何一个任务暂停或者失败时则踢出执行队列,寻找大文件对象数组中下一个ready状态任务进行顺序上传; 顺序上传,由于请求是异步的,要保证上传的顺序性,则使用Promise对象对每一片进行上传操作,使用async/await 也可;根据执行队列中的image_id+chunk寻找到需要上传的分片上传到后端;
const promise = new Promise(function(resolve, reject) {
  // ... some code
  if (/ 异步操作成功 /){
    resolve(value);
  } else {
    reject(error);
  }
});
  • 上传错误重试机制,由于上传过程在某一片可能存在上传错误,为了不影响整个流程的连贯性, 设置异常重试机制upload_retry = 3; 重试3次依然失败则将该条上传记录status 重置为 failed 上传失败. 并给出错误提示“上传中断,请稍后重试”,点击继续上传后则从current_chunk+1处继续上传;
  • 分片合并,由于每上传一片后端都会merge,那么前端可根据current_chunk === total_chunks 进行判断是否所有分片上传完毕并完成merge;如果当前分片等于总分片则大文件上传完成, 每次上传携带current_chunk和total_chunks标识到后端;
  • 4.4 暂停/继续上传

    • 点击暂停,如果存在多个任务(>max_concurrent_tasks)时,点击暂停更新当前大文件对象current_chunk以及prograss数据,并将当前任务从+ + + tasks_queue中剔除并从images对象数组中寻找ready状态的大文件对象的自动进行顺序上传;
    • 继续上传,failed和paused状态均可继续上传,点击继续上传检查是否还能加入执行任务队列(<max_concurrent_tasks),如果能则可以直接加入队列执行,如果不能则提示“当前上传队列已满,请稍后再试!”;
  • 4.5 取消上传

    • 取消上传,从执行队列踢出并标记为暂停状态,发送http请求到后端取消上传接口删除文件碎片和该大文件对象,从images 对象数组中踢出;该条记录消失在当前页;如果取消失败,则当前上传任务走手动继续上传流程;
  • 4.6 上传进度条

    • 通过切片数量和已上传切片数量计算进度 (current_chunk/total_chunks)* 100, 算出总的分段进度 chunk_progess
    • 通过axios请求库提供的onUploadProgress方法计算每一段切片的http上传进度从而得出精确的实时进度 progress = chunk_progess + uploadProgress
  • 4.7 上传速度
    • 记录开始上传的时间戳。
    • 在每个分片上传完成时,记录当前时间戳,并计算该分片的大小。
    • 根据当前时间戳和开始上传的时间戳,计算已经上传的总时间。
    • 根据已上传的总大小和总时间,计算上传速度,即已上传的总大小除以总时间
    • uploadProgress * chunk_size = 实时上传大小

5. 重点测试

5、涉及接口:

  1. 创建大文件
  2. 分片上传接口
  3. 取消上传接口(删除大文件)
  4. 获取大文件列表