文件分片上传

<input type="file" />
fileUpload() {
  const num = 1;
  const file = document.querySelector('input[type=file]').files[0];
  // const file = $("#file")[0].files[0];
  // this.msg.split('').reverse().join()
  // 声明一个FormData对象
  const formData = new FormData();
  const time = new Date().getTime();
  // 每片文件大小为5M
  const blockSize = 5 * 1024 * 1024;
  const blockNum = Math.ceil(file.size / blockSize);
  const nextSize = Math.min(num * blockSize, file.size);
  const fileData = file.slice((num - 1) * blockSize, nextSize);
  formData.append('file', fileData)
  // 文件名
  formData.append('name', file.name)
  // 总片数
  formData.append('chunks', blockNum.toString())
  formData.append('md5', time.toString())
  formData.append('uid', '13570')

  let config = {
    headers: {
      'Content-Type': 'multipart/form-data;boundary = ' + new Date().getTime()
    }
  }

  axios.post('http://xxx/fileUpload', formData, config).then(response => (
    this.info = response
  )).catch((error: Error) => { // 请求失败处理
    console.log(error)
  })
}

文件分片下载

axios.download = async (url: string, params: any = null, fileName: string = null, onDownloadProgress: (progressEvent: any) => {}) => {
  // 提前请求头部信息获取文件大小
  const response = await axios.head(url, {params})
  const contentLength = response.headers["content-length"]
  if (contentLength == null) {
    Notification.error("下载文件资源不存在!")
    return
  }
  // 是否支持分片传输
  const canSplice = response.headers["accept-ranges"] == "bytes"

  // 设置分片下载
  let concurrency_num = 1; // 并发数量
  let start = 0, end = -1

  if (contentLength / SizeUnits.GigaByte > 0.2) { // > 500M
    if (onDownloadProgress == null) {
      Notification.info({title: "系统提示", message: `下载文件资源可能过大,请稍后...`, position: 'bottom-right', duration: 5000})
    }
    if (canSplice) {
      concurrency_num *= Math.ceil(contentLength / SizeUnits.GigaByte * 10) // 设置并发下载数量: 1个线程下载100M
    }
  }

  const result = {
    filename: fileName,
    mime: response.headers["content-type"],
    blobMap: new Map<number, []>()
  }

  if (fileName == null) {
    const dispositions = response.headers["content-disposition"].split(";");
    const fileField = dispositions.filter(it => it.indexOf("filename=") > -1)
    result.fileName = fileField.length > 0 ? fileField[0].split("=")[1] : new Date().getTime()
  }

  function finish() {
    const blob_arr = []
    for(let i = 0; i < concurrency_num;i ++) {
      blob_arr.push(result.blobMap.get(i))
    }
    const blob = new Blob(blob_arr, {type: result.mime});
    const blobUrl = URL.createObjectURL(blob);
    const link = document.createElement("a");
    link.setAttribute('download', result.fileName || Math.random().toString())
    link.href = blobUrl;
    // document.body.appendChild(link)
    link.click();
    // document.body.removeChild(link)

    Notification.success({title: "系统提示", message: `资源文件[${link.getAttribute("download")}]下载完成,请查看下载列表!`, position: 'bottom-right', duration: 5000})
  }

  const splice = Math.ceil(contentLength / concurrency_num)
  let finish_counter = 0

  for (let i = 0; i < concurrency_num; i++) {
    start = i * splice
    end = (i + 1) * splice - 1

    console.log("start thread : ", i)
    axios.get(url, {
      responseType: 'blob',
      params,
      headers: {
        range: `bytes=${start}-${end > contentLength ? contentLength - 1 : end}`
      },
      onDownloadProgress
    }).then((resp) => {
      finish_counter += 1
      console.log("result: ", i, finish_counter, concurrency_num, resp.data)
      result.blobMap.set(i, resp.data)
      if (finish_counter == concurrency_num) {
        finish()
      }
    }).catch((error: Error) => {
      Notification.error(error.message)
    })
  }
}

参考资料