当前位置: 首页 > article >正文

大文件上传的解决办法~文件切片、秒传、限制文件并发请求。。。

1、项目背景:针对大文件上传,如果将文件作为一个请求去发送给后端,会有以下几种问题,首先是上传时间长,用户不能进行其他操作,包括页面刷新等操作,其次有的接口会设置响应时间限制,可能大文件还没上传完就触发响应限制了,这样对用户很不友好,那么怎么解决呢?

2、首先前端针对大文件使用文件切片技术,将大文件切成多个小文件,然后再将多个小文件传给后端,由后端进行组合即可。(文件切片)

<template>
  <div>
    <input type="file" @change="handleUpload" />
  </div>
</template>

<script setup>
import { ref } from 'vue';
const file = ref(null);
const chunk_size=1024*1024//每一个切片的大小(1M)
const chunks=ref([])//存储所有的切片
//文件上传函数
const handleUpload= async (e) => {
  const selectedFile = e.target.files[0]; // 拿到选择的文件的 files 文件数据
  if (!selectedFile ) return;
  file.value = selectedFile;
  fileName.value= selectedFile.name//存储文件名
  调用文件切片函数
  chunks.value = createFileChunk ()
  调用hash函数
  const hash = await calculateHash()
  fileHash.value=hash//存储文件hash
}
//文件切片函数
const createFileChunk = () => {
    let cur = 0//分片的下标
    let fileChunkList=[]//接收所有的分片
    //开始遍历文件
    while(cur < file.value.size){
        const blob = file.value.slice(cur,cur+chunk_size)//这里使用slice()方法进行剪切,值为开始下标和结束下标
        fileChunkList.push(blob)
        cur+=chunk_size//更新下标
    }
    return fileChunkList//向外抛出所有的切片
}

</script>

3、依据文件内容生成唯一的hash值,可以避免文件改名后重复上传的问题。

这里,我们使用 spark-md5.min.js 来根据文件的二进制内容计算文件的 hash值。用来实现秒传

引入spark-md5.min.js
import SparkMD5 from 'spark-md5'
//计算文件hash值
const calculateHash = () => {
    return Promise(resolve=>{
        1、第一个和最后一个切片全部参与计算。
        2、中间的切片只计算前面2个字节、中间2个字节、最后2给字节。
        const targets:Blob=[]//存储所有参与计算的切片
        const spark=new SparkMD5.ArrayBuffer()
        const fileReader=new FileReader()
        chunks.value.forEach((chunk,index)=>{
            if(index===0 || index===chunks.length-1){
                1、第一个和最后一个切片全部参与计算。
                targets.push(chunk)
            } else{
                2、中间的切片只计算前面2个字节、中间2个字节、最后2给字节。
                targets.push(chunk.slice(0,2)//前面2个字节
                targets.push(chunk.slice(chunk_size/2,chunk_size/2+2)//中间2个字节
                targets.push(chunk.slice(chunk_size-2,chunk_size)//后面2个字节
            }
        })
        fileReader.readAsArrayBuffer(new Blob(targets))
        fileReader.onload=(e)=>{
            spark.append((e.target as FileReader).result)
            console.log('hash值',spark.end())
            resolve(spark.end())
        }
    })
}

4、前面我们完成了文件上传的准备工作,下面写文件上传:

const fileHash = ref('');
const fileName = ref('');

const uploadChunks = async (chunks: Blob[]) => {
    const data = chunks.map((chunk, index) => {
        return {
            fileHash: fileHash.value, // 文件hash
            chunkHash: `${fileHash.value}-${index}`, // 文件切片hash
            chunk
        };
    });

    const formDatas = data.map(item => {
        const formData = new FormData();
        formData.append('chunk', item.chunk);
        formData.append('chunkHash', item.chunkHash);
        formData.append('fileHash', item.fileHash);
        return formData;
    });

    const max = 6; // 最大并发请求数
    let index = 0;
    const taskpool: Promise<Response>[] = []; // 请求池(当前正在处理的请求)

    while (index < formDatas.length || taskpool.length > 0) { // 代表文件未上传完或仍有请求在处理
        if (index < formDatas.length) {
            const task = fetch('upload', { method: 'POST', body: formDatas[index] }); // 发送请求
            taskpool.push(task); // 将新的请求(Promise)添加到 taskpool 中
            index++;
        }

        if (taskpool.length >= max) {
            const completedTask = await Promise.race(taskpool); // 等待 taskpool 中任意一个请求完成,然后继续循环
            taskpool.splice(taskpool.indexOf(completedTask), 1); // 将已完成的请求从任务池中移除
        }
    }

    await Promise.all(taskpool); // 确保所有请求都已完成
};


http://www.kler.cn/a/507377.html

相关文章:

  • 我的世界-与门、或门、非门等基本门电路实现
  • QT 如何禁止QComboBox鼠标滚轮
  • ASP.NET Core - .NET 6 以上版本的入口文件
  • C++ 文字识别OCR
  • 32单片机综合应用案例——智能家居灯光控制系统(二)(内附详细代码讲解!!!)
  • 卷积神经02-CUDA+Pytorch环境安装
  • Lambda 架构之实时处理层的深度剖析:从原理到 Java 实战
  • XML序列化和反序列化的学习
  • 50.AppendAllText C#例子
  • 成功案例分享 — 芯科科技助力涂鸦智能打造Matter over Thread模块,简化Matter设备开发
  • C#数据库操作系列---SqlSugar完结篇
  • 摄像头模块在狩猎相机中的应用
  • 【Unity-Animator】通过 StateMachineBehaviour 实现回调
  • 华为HCIE-Security考试心得
  • SpringMVC复习笔记
  • Oracle系列---【Smallfile模式的表空间如何确定单个数据文件的最大大小?】
  • 踏上 C++ 编程之旅:开篇之作
  • Observability:组装 OpenTelemetry NGINX Ingress Controller 集成
  • yt-dlp脚本下载音频可选设置代理
  • 探索 Linux:(一)介绍Linux历史与Linux环境配置
  • 鸿蒙UI开发——文本级联选择器
  • 基于Python招聘职位数据采集与数据可视化分析
  • 用 HTML5 Canvas 和 JavaScript 实现雪花飘落特效
  • 基于Matlab实现微带贴片天线仿真程序
  • 深入探索Vue.js 3中基于Composition API的动态组件开发
  • 源码编译http