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

分享三种网页文件上传下载的解决方案及其实现思路?

📅 开发者日志:大文件上传系统的艰难实现之路

项目背景

2023年11月15日,周三,晴转多云

今天正式接手了一个具有挑战性的外包项目——构建一个支持20GB超大文件传输的Web系统。客户要求苛刻但预算有限,作为一名个人开发者,这既是一次机遇也是巨大的挑战。

需求分析

核心功能需求

  1. 超大文件支持:单文件20GB传输
  2. 批量传输:包含上千文件的文件夹层级结构保持
  3. 安全要求:SM4/AES加密传输与存储
  4. 稳定性:断点续传需持久化保存进度
  5. 兼容性:必须支持IE8等老旧浏览器

技术栈确认

  • 前端:Vue3 + WebUploader/原生H5
  • 后端:ASP.NET Core (.NET 8)
  • 数据库:SQL Server
  • 存储:阿里云OSS
  • 跨平台支持:Windows/macOS/Linux全平台

技术难点突破

文件夹结构保持方案

// 文件夹上传处理逻辑classFolderUploader{constructor(){this.folderStructure=newMap();// 使用Map保存完整路径}processEntry(entry,path=''){returnnewPromise((resolve)=>{if(entry.isFile){entry.file(file=>{constfullPath=`${path}/${file.name}`;this.folderStructure.set(fullPath,file);resolve();});}elseif(entry.isDirectory){constdirReader=entry.createReader();dirReader.readEntries(entries=>{constpromises=entries.map(subEntry=>this.processEntry(subEntry,`${path}/${entry.name}`));Promise.all(promises).then(resolve);});}});}}

断点续传持久化方案

// ASP.NET Core 断点续传状态管理publicclassUploadStateService{privatereadonlyConcurrentDictionary_stateCache;publicUploadStateService(){_stateCache=newConcurrentDictionary();}publicvoidSaveState(stringfileId,longchunkIndex){varstate=_stateCache.GetOrAdd(fileId,id=>newUploadState(id));state.UploadedChunks.Add(chunkIndex);// 持久化到数据库usingvardb=newAppDbContext();db.UploadStates.Update(state.ToEntity());db.SaveChanges();}publicUploadStateGetState(stringfileId){if(_stateCache.TryGetValue(fileId,outvarstate)){returnstate;}// 从数据库加载usingvardb=newAppDbContext();varentity=db.UploadStates.Find(fileId);returnentity?.ToModel()??newUploadState(fileId);}}

前后端完整交互示例

前端加密上传实现

// 基于WebUploader的加密上传组件exportclassSecureFileUploader{constructor(options){this.uploader=WebUploader.create({swf:'/libs/Uploader.swf',server:options.uploadUrl,chunked:true,chunkSize:4*1024*1024,// 4MB分片threads:3,prepareNextFile:true,fileSizeLimit:20*1024*1024*1024// 20GB});this.initEvents();this.cryptoWorker=newWorker('/js/crypto.worker.js');}initEvents(){this.uploader.on('uploadBeforeSend',(obj,data)=>{returnnewPromise(resolve=>{this.cryptoWorker.postMessage({type:'encrypt',data:obj.file,algorithm:'SM4'});this.cryptoWorker.onmessage=(e)=>{data.file=e.data;resolve(data);};});});this.uploader.on('fileQueued',file=>{conststate=localStorage.getItem(`upload_${file.id}`);if(state){this.uploader.uploader.upload(file,JSON.parse(state));}});}}

后端分片处理实现

// ASP.NET Core 文件分片控制器[ApiController][Route("api/upload")]publicclassUploadController:ControllerBase{privatereadonlyUploadStateService_stateService;privatereadonlyIOSSClient_ossClient;publicUploadController(UploadStateServicestateService,IOSSClientossClient){_stateService=stateService;_ossClient=ossClient;}[HttpPost("chunk")]publicasyncTaskUploadChunk([FromForm]IFormFilefile,[FromForm]stringfileId,[FromForm]intchunkIndex,[FromForm]inttotalChunks){usingvarmemoryStream=newMemoryStream();awaitfile.CopyToAsync(memoryStream);// 解密处理vardecryptedData=CryptoHelper.SM4Decrypt(memoryStream.ToArray(),Configuration["EncryptionKey"]);// 存储到OSSvarchunkKey=$"{fileId}/{chunkIndex}";await_ossClient.PutObjectAsync("uploads",chunkKey,newMemoryStream(decryptedData));// 更新状态_stateService.SaveState(fileId,chunkIndex);if(chunkIndex==totalChunks-1){// 触发文件合并BackgroundJob.Enqueue(()=>MergeFileChunks(fileId));}returnOk(new{success=true});}[NonAction]publicasyncTaskMergeFileChunks(stringfileId){varstate=_stateService.GetState(fileId);varfinalKey=$"files/{DateTime.Now:yyyyMMdd}/{fileId}";usingvarfinalStream=newMemoryStream();foreach(varchunkinstate.UploadedChunks.OrderBy(x=>x)){varchunkKey=$"{fileId}/{chunk}";varchunkData=await_ossClient.GetObjectAsync("uploads",chunkKey);awaitchunkData.CopyToAsync(finalStream);await_ossClient.DeleteObjectAsync("uploads",chunkKey);}finalStream.Position=0;await_ossClient.PutObjectAsync("final",finalKey,finalStream);}}

兼容性处理方案

IE8兼容层实现

// ie8-wrapper.js(function(){// Polyfill for File APIif(!window.File){window.File=function(){};window.FileReader=function(){this.readAsArrayBuffer=function(blob){// IE8的ActiveX实现varaxo=newActiveXObject("ADODB.Stream");axo.Type=1;// 二进制类型axo.Open();axo.LoadFromFile(blob.name);varbuffer=axo.Read();this.onload({target:{result:buffer}});};};}// Polyfill for FormDataif(!window.FormData){window.FormData=function(){this.append=function(key,value){// 使用隐藏iframe实现表单提交variframe=document.createElement('iframe');iframe.name='formdata-iframe';document.body.appendChild(iframe);varform=document.createElement('form');form.target=iframe.name;form.method='POST';form.enctype='multipart/form-data';varinput=document.createElement('input');input.type='hidden';input.name=key;input.value=value;form.appendChild(input);document.body.appendChild(form);form.submit();};};}})();

开发文档结构

📂 项目文档 ├── 1. 系统架构设计 │ ├── 1.1 技术栈说明 │ ├── 1.2 系统架构图 │ └── 1.3 部署拓扑图 ├── 2. API接口文档 │ ├── 2.1 上传接口规范 │ ├── 2.2 下载接口规范 │ └── 2.3 状态管理接口 ├── 3. 前端集成指南 │ ├── 3.1 WebUploader配置 │ ├── 3.2 加密模块使用 │ └── 3.3 兼容性处理 ├── 4. 后端部署手册 │ ├── 4.1 环境配置 │ ├── 4.2 数据库初始化 │ └── 4.3 性能调优 └── 5. 运维监控 ├── 5.1 日志收集 ├── 5.2 异常告警 └── 5.3 扩容方案

项目总结

已解决问题

  1. 通过分片加密上传实现了20GB文件支持
  2. 使用目录树遍历算法保持文件夹结构
  3. 结合本地存储和数据库实现持久化断点续传
  4. 开发多套降级方案保证IE8兼容性

待解决问题

  1. 极端网络环境下分片成功率优化
  2. OSS批量操作的性能瓶颈
  3. 国产浏览器(红莲花等)的特殊适配

后记:这个项目让我深刻体会到企业级文件传输的复杂性。欢迎同行加入QQ群374992201交流大文件传输技术,共同应对外包项目中的各种挑战。

设置框架

安装.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

创建数据库

配置数据库连接信息

检查数据库配置

访问页面进行测试


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

效果预览

文件上传

文件刷新续传

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

文件夹上传

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

下载完整示例

下载完整示例

http://www.cnnetsun.cn/news/800360.html

相关文章:

  • 通义千问3-14B性能极限?A100上120 token/s部署实测
  • 工业触摸屏:Elo、AMT 和 Microchip
  • 零基础入门Glyph视觉推理,一键启动长文本理解新方式
  • 【风电功率预测】别再只卷模型了:提准最快的捷径,是把“输入稳定性”做成硬指标
  • Tampermonkey篡改猴200+插件打包下载
  • 为什么Qwen3-14B能省事?128k长文单卡推理部署解析
  • 基于深度学习的行人追踪系统
  • 零配置起步!Unsloth开箱即用的本地AI训练体验
  • 利刃藏于调度:XXL-JOB越权漏洞全维度解析与前瞻性防御
  • whoami.exe文件丢失找不到 免费下载方法分享
  • 《把脉行业与技术趋势》-92-蒸汽机的煤炭能量转化成运动动力的过程
  • Live Avatar enable_vae_parallel作用说明:多GPU优化技巧
  • 看完就想试!UNet打造的跨年龄人脸融合作品展示
  • 修改德哥的PostgreSQL求解数独SQL在cedardb上运行
  • 2026年多模态模型趋势入门必看:Glyph开源框架+弹性GPU部署指南
  • 又有新项目了,开整?
  • SGLang支持Qwen3-1.7B?推理加速配置全讲解
  • 【Django毕设全套源码+文档】基于django推荐算法在汽车营销中的设计与实践(丰富项目+远程调试+讲解+定制)
  • 【Django毕设全套源码+文档】基于Python的邮件分类系统的设计与实现(丰富项目+远程调试+讲解+定制)
  • Glyph医疗辅助诊断:医学影像报告生成系统实战
  • 麦橘超然镜像适合哪些人群?这三类人最受益
  • 如何用YOLO11做自动标注?真实项目经验分享
  • 【Django毕设源码分享】基于Django的网上租车系统的设计与实现(程序+文档+代码讲解+一条龙定制)
  • 大模型部署新方式:GPT-OSS+WEBUI轻量化实践
  • Windows 操作系统下安装 make 工具的方法
  • 如何用YOLOv12镜像训练自定义数据集?保姆级教程
  • 修改DIFY源代码,构建新镜像的方法
  • YOLOv10工程化交付实践,MLOps思维落地
  • WinDbg Preview下载与内核态调试环境搭建:新手教程
  • 企业办公新方案!Open-AutoGLM自动处理日报周报