前端的大文件上传

451 阅读2分钟

前端的大文件上传

前言: 话不多说,直入主题吧。

Main

实现大文件上传的一种常见方式是通过分片上传,即将大文件分成若干个小文件,分别上传到服务器端,最终将它们合并成一个完整的文件。这种方式能够有效地避免上传过程中的网络中断和超时等问题,同时也能够提高上传速度和稳定性。

具体来说,实现分片上传需要以下步骤:

  1. 将大文件切分成若干个小文件,通常每个小文件的大小应该在1MB到10MB之间,可以根据实际情况进行调整。
  2. 将每个小文件分别上传到服务器端,可以使用HTTP协议的POST方法进行上传,将小文件作为请求体发送到服务器端。
  3. 服务器端接收到每个小文件后,将它们保存在临时文件夹中,等待所有分片上传完成后进行合并。
  4. 在上传每个小文件的同时,还需要上传一些附加信息,如文件名称、文件大小、文件类型等,这些信息可以作为请求参数一起发送到服务器端。
  5. 在所有分片上传完成后,需要向服务器端发送一个合并请求,告知服务器端哪些小文件需要进行合并,服务器端收到请求后将小文件合并为一个完整的文件,保存到指定的文件夹中。

如果上传某个分片失败了,我们可以将这个失败的分片进行重传,或者直接中断整个文件的上传过程。具体的处理方式取决于实际的业务需求。一般来说,我们可以通过前端实现一个重试机制,在上传失败后自动重新发送该分片的请求,重试的次数可以根据实际情况进行设置。

此外,为了保证上传的可靠性,我们还可以在服务器端实现一个接收到分片后进行校验的逻辑,确保分片上传的正确性。例如,服务器端可以计算分片数据的MD5值,并将其与客户端传递的MD5值进行比对,如果不一致则说明分片上传出现了问题,需要进行重传。

以下是一个在上传过程中检测并重传失败分片的示例代码,仅供参考:

<template>
  <div>
    <input type="file" @change="handleFileChange" />
    <button @click="uploadFile">上传文件</button>
  </div>
</template>

<script>
import { ref } from 'vue'

export default {
  setup() {
    const fileInput = ref(null)
    const chunkSize = 1 * 1024 * 1024 // 分片大小为1MB
    let file = null

    // 处理文件选择事件
    const handleFileChange = (e) => {
      file = e.target.files[0]
    }

const formIndexdata = (index) => {
    const start = index * chunkSize
    const end = Math.min(start + chunkSize, file.size)
    const chunk = file.slice(start, end)
    const formData = new FormData()
    formData.append('file', chunk)
    formData.append('name', file.name)
    formData.append('type', file.type)
    formData.append('size', file.size)
    formData.append('index', index)
    formData.append('totalChunks', totalChunks)
    return formData;
}
 // 定义重传分片的函数
 const retryChunk = (index) => {
    let formData = formIndexdata(index)
    // 发送分片上传请求
    axios.post('/api/upload', formData).then((res) => {
        console.log(`上传第${index + 1}个分片成功`)
        chunkStatus[index] = true
    }).catch((err) => {
        console.error(`上传第${index + 1}个分片失败:${err.message}`)
        setTimeout(() => {
            retryChunk(index) // 重试上传
        }, 5000) // 5秒后重试
    })
}
const uploadFile = () => {
    if (!file) {
        console.error('请选择要上传的文件')
        return
    }
    // 计算文件总共需要切分成多少个分片
    const totalChunks = Math.ceil(file.size / chunkSize)
    // 初始化分片上传状态数组
    const chunkStatus = new Array(totalChunks).fill(false)
    // 循环上传每个分片
    for (let i = 0; i < totalChunks; i++) {
        let formData = formIndexdata(i)
        // 发送分片上传请求
        axios.post('/api/upload', formData).then((res) => {
            console.log(`上传第${i + 1}个分片成功`)
            chunkStatus[i] = true
        }).catch((err) => {
            console.error(`上传第${i + 1}个分片失败:${err.message}`)
            retryChunk(i) // 重试上传
        })
    }
    // 检测分片上传状态并发送合并请求
    const checkInterval = setInterval(() => {
        if (chunkStatus.every(status => status)) {
            clearInterval(checkInterval)
            axios.post('/api/merge', { name: file.name, size: file.size, totalChunks }).then((res) => {
                console.log('合并文件成功')
            }).catch((err) => {
                console.error(`合并文件失败:${err.message}`)
            })
        }
    }, 1000) // 每隔1秒检测一次分片上传状态
}
return {
  fileInput,
  handleFileChange,
  uploadFile,
}
}
}
</script>

注: 一般情况我们会对axios进行封装,然后在需要的地方调用;文件切片的大小和切片重传的机制和具体实际项目有关,这里只是一种思想。

结束语:如果对您有帮助!点个赞。加个关注吧,有问题评论区留言交流哦!