news 2026/3/4 21:19:05

交流一下大文件上传组件的优化经验

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
交流一下大文件上传组件的优化经验

(抱紧保温杯在星巴克敲键盘版)
各位同行好!我是上海某咖啡馆·野生.NET程序员·刚搞懂IIS怎么念的·代码民工·秃头预备役。最近接了个"史诗级"外包项目,客户要求实现20G文件夹上传下载,现在每天的状态be like:

💻 前端:Vue3 + 原生JS魔改
🖥️ 后端:ASP.NET WebForm(连MVC都不敢用)
📂 数据库:SQL Server(存储文件元数据)
💰 预算:100元(含咖啡续命钱)


🎯 前端の求生指南(Vue3 + 原生JS兼容IE8版)

// 兼容IE8的文件夹上传组件(基于WebUploader魔改)classIE8FolderUploader{constructor(){this.fileTree={};// 存储文件层级结构this.chunkSize=10*1024*1024;// 10MB分片(IE8友好)this.initFileInput();// 初始化文件选择控件}// 初始化文件输入(兼容IE8的降级方案)initFileInput(){constinput=document.createElement('input');input.type='file';input.id='folderInput';input.style.display='none';// IE8专用:通过document.createEventObject模拟事件if(document.all&&!window.atob){input.setAttribute('multiple','multiple');input.onchange=(e)=>this.handleIE8Files(e);}else{input.setAttribute('webkitdirectory','');input.onchange=(e)=>this.handleModernFiles(e);}document.body.appendChild(input);}// IE8文件处理(递归遍历伪文件夹结构)handleIE8Files(event){constfiles=event.target.files;constfakeTree={};// IE8无法获取真实路径,用文件名模拟层级(如"部门A/项目1/文件.txt")for(leti=0;i<files.length;i++){constpathParts=files[i].name.split('/');letcurrentNode=fakeTree;// 递归构建虚拟目录for(letj=0;j<pathParts.length-1;j++){constdir=pathParts[j];if(!currentNode[dir])currentNode[dir]={};currentNode=currentNode[dir];}constfileName=pathParts.pop();currentNode[fileName]=files[i];// 存储文件对象}this.fileTree=fakeTree;this.startUpload();}// 现代浏览器文件夹处理handleModernFiles(event){constfiles=event.target.files;constrealTree={};for(leti=0;i<files.length;i++){constfile=files[i];constpath=file.webkitRelativePath||file.name;constparts=path.split('/');letnode=realTree;// 构建真实目录结构for(letj=0;j<parts.length-1;j++){constdir=parts[j];if(!node[dir])node[dir]={};node=node[dir];}node[parts.pop()]=file;}this.fileTree=realTree;this.startUpload();}// 分片上传(带断点续传)startUpload(){// 使用userData(IE8专属)存储进度conststorage=window.localStorage||(function(){constdiv=document.createElement('div');div.addBehavior('#default#userData');document.body.appendChild(div);return{setItem:(key,value)=>{div.setAttribute(key,value);div.save('uploader');},getItem:(key)=>div.getAttribute(key)};})();this.traverseTree(this.fileTree,'',storage);}// 递归遍历文件树traverseTree(node,parentPath,storage){for(constkeyinnode){if(node[key]instanceofFile){constfile=node[key];constrelativePath=parentPath?`${parentPath}/${key}`:key;constfileId=this.generateFileId(file,relativePath);// 检查断点续传进度constsavedChunk=parseInt(storage.getItem(`chunk_${fileId}`)||'0');consttotalChunks=Math.ceil(file.size/this.chunkSize);for(leti=savedChunk;i<totalChunks;i++){constblob=file.slice(i*this.chunkSize,(i+1)*this.chunkSize);constformData=newFormData();formData.append('file',blob);formData.append('chunkIndex',i);formData.append('totalChunks',totalChunks);formData.append('fileId',fileId);formData.append('relativePath',relativePath);// IE8专用:使用ActiveXObject发送请求constxhr=window.XMLHttpRequest?newXMLHttpRequest():newActiveXObject("Microsoft.XMLHTTP");xhr.open('POST','/api/upload',true);xhr.onload=()=>{if(xhr.status===200){storage.setItem(`chunk_${fileId}`,i+1);if(i===totalChunks-1){console.log(`${relativePath}上传完成!`);}}};xhr.send(formData);}}else{// 递归处理子目录this.traverseTree(node[key],`${parentPath}/${key}`,storage);}}}}// 在Vue组件中使用exportdefault{mounted(){this.uploader=newIE8FolderUploader();},methods:{triggerUpload(){document.getElementById('folderInput').click();}}}

💡 后端の求生代码(ASP.NET WebForm版)

// 文件上传处理(WebForm后台代码)publicpartialclassUploadHandler:System.Web.UI.Page{protectedvoidPage_Load(objectsender,EventArgse){if(Request.HttpMethod=="POST"){try{// 获取参数varfileId=Request.Form["fileId"];varchunkIndex=int.Parse(Request.Form["chunkIndex"]);vartotalChunks=int.Parse(Request.Form["totalChunks"]);varrelativePath=Request.Form["relativePath"];// 获取文件分片varfile=Request.Files["file"];vartempPath=Server.MapPath($"~/App_Data/Temp/{fileId}_{chunkIndex}");file.SaveAs(tempPath);// 如果是最后一个分片,合并文件if(chunkIndex==totalChunks-1){MergeChunks(fileId,totalChunks,relativePath);Response.Write("{\"status\":\"complete\"}");}else{Response.Write("{\"status\":\"success\"}");}}catch(Exceptionex){Response.Write($"{{\"error\":\"{ex.Message}\"}}");}}}privatevoidMergeChunks(stringfileId,inttotalChunks,stringrelativePath){vartempDir=Server.MapPath($"~/App_Data/Temp/");varfinalPath=Server.MapPath($"~/Uploads/{relativePath}");// 确保目录存在vardir=Path.GetDirectoryName(finalPath);if(!Directory.Exists(dir))Directory.CreateDirectory(dir);// 合并分片using(varfs=newFileStream(finalPath,FileMode.Create)){for(inti=0;i<totalChunks;i++){varchunkPath=Path.Combine(tempDir,$"{fileId}_{i}");varbytes=File.ReadAllBytes(chunkPath);fs.Write(bytes,0,bytes.Length);File.Delete(chunkPath);// 清理临时文件}}// 加密存储(示例:AES加密)EncryptFile(finalPath);}privatevoidEncryptFile(stringfilePath){// 实际项目中替换为SM4/AES加密实现// 这里仅作示例,实际加密需使用BouncyCastle等库File.WriteAllText(filePath+".enc","加密后的内容占位符");File.Delete(filePath);}}

📢 紧急求助(预算100元版)

当前系统存在以下要命问题

  1. IE8加密传输ActiveXObject无法直接处理加密(求C#端解密方案)
  2. 万级文件下载:非打包下载会触发浏览器连接数限制(求分批次下载方案)
  3. 断点续传可靠性:重启电脑后userData可能丢失(求SQL Server进度存储方案)

求各位大佬加群374992201拯救!现在入群可享:

  • 免费获得《如何在100元预算下完成外包项目》电子书
  • 参与"帮同行改BUG"活动赢取辣条基金
  • 推荐项目成功送《如何优雅拒绝客户改需求》秘籍

(突然正经)PS:真的求后端师傅!本人擅长:

  • 熬夜改前端兼容性问题
  • 写注释骗客户验收
  • PPT画大饼
  • 帮师傅买咖啡

联系方式:QQ群374992201(暗号:我要接单)
群内活动:

  1. 新人入群送1-99元红包
  2. 推荐项目得20%分成
  3. 超级会员享50%利润(未来项目)

**求同行推荐项目!**本人要求不高:

  • 预算够买咖啡
  • 客户不频繁改需求
  • 能用VS2022开发
  • 合同款能按时结的优先

(最后喊话)甲方爸爸们看过来!

  • 可提供100元预算的完整解决方案
  • 支持IE8到Edge全浏览器
  • 赠送7×24小时人工智障客服
  • 现在签约送《如何让客户放弃加密功能》话术手册!

设置框架

安装.NET Framework 4.7.2
https://dotnet.microsoft.com/en-us/download/dotnet-framework/net472
框架选择4.7.2

添加3rd引用

编译项目

NOSQL

NOSQL无需任何配置可直接访问页面进行测试

SQL

使用IIS
大文件上传测试推荐使用IIS以获取更高性能。

使用IIS Express

小文件上传测试可以使用IIS Express

创建数据库

配置数据库连接信息

检查数据库配置

访问页面进行测试


相关参考:
文件保存位置,

效果预览

文件上传

文件刷新续传

支持离线保存文件进度,在关闭浏览器,刷新浏览器后进行不丢失,仍然能够继续上传

文件夹上传

支持上传文件夹并保留层级结构,同样支持进度信息离线保存,刷新页面,关闭页面,重启系统不丢失上传进度。

下载完整示例

下载完整示例

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/3/4 4:05:31

模型太大加载不了?SenseVoiceSmall轻量版部署替代方案探讨

模型太大加载不了&#xff1f;SenseVoiceSmall轻量版部署替代方案探讨 在语音识别领域&#xff0c;大模型虽然精度高&#xff0c;但对硬件要求严苛&#xff0c;动辄需要24G以上显存才能加载。很多开发者在本地或边缘设备上尝试部署时&#xff0c;常常遇到“CUDA out of memory…

作者头像 李华
网站建设 2026/3/4 11:19:24

【企业级Maven管理秘籍】:大规模项目中如何零失误处理依赖冲突

第一章&#xff1a;企业级Maven依赖管理的核心挑战 在大型企业级Java项目中&#xff0c;Maven作为主流的构建与依赖管理工具&#xff0c;其依赖管理体系的复杂性随着项目规模扩大而急剧上升。多个模块、多团队协作以及第三方库的频繁引入&#xff0c;使得依赖冲突、版本不一致和…

作者头像 李华
网站建设 2026/3/4 13:14:50

Spring MVC与Spring Security中CORS配置的那些坑,你踩过几个?

第一章&#xff1a;Java解决跨域问题CORS配置 在前后端分离的开发架构中&#xff0c;浏览器出于安全考虑实施同源策略&#xff0c;导致前端应用无法直接请求不同源的后端接口。跨域资源共享&#xff08;CORS&#xff09;是一种W3C标准&#xff0c;允许服务器声明哪些外部源可以…

作者头像 李华
网站建设 2026/3/3 16:49:30

百万级Excel导出不OOM、不超时、不阻塞主线程——阿里系高并发导出架构设计(含完整Spring Boot响应式实现)

第一章&#xff1a;百万级Excel导出的核心挑战与架构目标 在企业级应用中&#xff0c;面对百万级数据量的Excel导出需求&#xff0c;传统同步导出方式极易引发内存溢出、响应超时和系统阻塞等问题。如何在保障系统稳定性的前提下高效完成大数据量导出&#xff0c;成为后端架构设…

作者头像 李华
网站建设 2026/3/4 7:14:32

理解 envFrom.secretRef 应用

一、核心含义&#xff1a;一句话理解 envFrom.secretRef envFrom: - secretRef: {name: my-secret} 的本质是&#xff1a; 把 K8s 中名为 my-secret 的 Secret 资源里的所有「键值对」&#xff0c;自动转换成容器内的「环境变量」&#xff0c;应用代码可以直接通过读取环境变量…

作者头像 李华