世外天堂

世外天堂

代码、番剧与灵感共振的赛博据点

首页前端大文件上传分片断点续传

前端大文件上传分片/断点续传/并发控制实现

📅 2026年5月10日✍️ 762 字⏱ 3 分钟阅读 👁 -- 次阅读

前端大文件上传分片、断点续传

const chunkSize = 1024 * 1024 // 1MB

function createChunks(file) {
    const chunks = []

    let start = 0

    while (start < file.size) {
        chunks.push(file.slice(start, start + chunkSize))
        start += chunkSize
    }

    return chunks
}

为什么需要 hash/md5?

  1. 校验文件完整性
  2. 避免重复上传

前端如何计算 hash?

npm i spark-md5
import SparkMD5 from 'spark-md5'

async function calculateHash(file: File) {
  return new Promise((resolve) => {
    const spark = new SparkMD5.ArrayBuffer()

    const reader = new FileReader()

    reader.readAsArrayBuffer(file)

    reader.onload = (e) => {
      spark.append(e.target?.result as ArrayBuffer)

      resolve(spark.end())
    }
  })
}

查询已上传分片

const res = await fetch(`/check?hash=${fileHash}`)

const uploadedChunks = await res.json()//[0,1,2]

只上传缺失部分

async function uploadFile(file) {
    const chunks = createChunks(file)

    const uploadedChunks = await getUploadedChunks()

    for (let index = 0; index < chunks.length; index++) {
        //核心
        if (uploadedChunks.includes(index)) {
            continue
        }

        const formData = new FormData()

        formData.append('file', chunks[index])
        formData.append('hash', fileHash)
        formData.append('index', index)

        await fetch('/upload', {
            method: 'POST',
            body: formData
        })
    }

    await mergeChunks()
}

通知后端合并

await fetch('/merge', {
    method: 'POST',
    headers: {
        'Content-Type': 'application/json'
    },
    body: JSON.stringify({
        hash: fileHash,
        fileName: file.name
    })
})

上传进度怎么算?

onUploadProgress中拿到loaded和total

现代框架用哪些库?

ali-oss

import OSS from 'ali-oss'

const client = new OSS({
  region: 'oss-cn-hangzhou',
  accessKeyId: 'xxx',
  accessKeySecret: 'xxx',
  bucket: 'test',
})

await client.multipartUpload(
  file.name,
  file,
  {
    parallel: 4,
    partSize: 1024 * 1024,
    progress(p) {
      console.log(p)
    },
  }
)

simple-uploader.js

<template>
  <uploader
    :options="options"
    @file-success="fileSuccess"
  >
    <uploader-btn>选择文件</uploader-btn>

    <uploader-list />
  </uploader>
</template>

<script setup>
const options = {
  target: '/api/upload',

  chunkSize: 2 * 1024 * 1024,

  testChunks: true
}

function fileSuccess() {
  console.log('上传完成')
}
</script>

世外天堂

代码、番剧与灵感共振的赛博据点

© 2026 小翼·访客 --·浏览 --