大文件上传思路,以及实现

4 分钟

思路:

前端拿到文件后,对文件进行切片操作,然后每个分片发送请求给到后端,所有切片都请求成功后,发送一个合并请求,后端进行文件合并

核心代码如下:

  const handleCustomRequest = async ({ file }: { file: File }) => {  
    if(!file) return
    // 切片
    const fileChunkList = createFileChunk(file)
    filesListInfo.current = fileChunkList.map(() => 0)
    try {
      if(fileChunkList.length > 0){
        const formDataFirst = new FormData()
        formDataFirst.append("file", fileChunkList[0]?.file)
        setLoading(true)
        const res = await uploadFile(formDataFirst, (e: ProgressEvent) => onUploadProgress(e, 0))
        if(fileChunkList.length > 1){
          for (let i = 1; i < fileChunkList.length; i++) {  
            const formData = new FormData()
            formData.append("file", fileChunkList[i].file)
            formData.append("uploadId", res.data.uploadId)
            await uploadFile(formData, (e: ProgressEvent) => onUploadProgress(e, i))
          }
        }
        // 合并
        await mergeUploadFile({ uploadId: res?.data?.uploadId })
        message.success(f('上传成功'))
        setLoading(false)
        refreshInfo()
      }
    } catch (error) {
      message.error(error?.response?.data?.msg || f('上传失败'))
      setLoading(false)
    }
  }

切片

  const createFileChunk = (file: File, size = SIZE) => {
    const fileChunkList: {file: Blob}[] = []
    let cur = 0
    while (cur < file.size) {
      fileChunkList.push({ file: file.slice(cur, cur + size) })
        cur += size
      }
    return fileChunkList
  }

滚动条展示

前端已知切片总数 Process = 所有切片进度累加 / 总进度

  const onUploadProgress = (progressEvent: ProgressEvent, index: Number) => {
    const percentCompleted = Math.round((progressEvent.loaded * 100) / progressEvent.total)
    filesListInfo.current[index] = percentCompleted
    const newProcess = (filesListInfo.current.reduce((pre, cur)=>{
      return pre + cur
    }, 0) / (filesListInfo.current.length))
    setProcess(newProcess)
  }

优化 1、暂停上传 2、断点续传 3、文件秒上传(已经上传过的文件)


此文自动发布于:github issues