大文件传输解决方案设计
项目背景与需求分析
作为江西某软件公司的前端工程师,我面临一个具有挑战性的文件传输需求场景:
- 超大文件传输:支持20G单文件传输,100G+的10万级文件夹传输
- 全平台兼容:包括IE8、国产浏览器和多种国产操作系统
- 安全要求:支持SM4/AES加密传输和存储
- 模块化设计:提供前后端完整源代码,易于集成
- 可靠性要求:需要解决现有WebUploader方案的问题(进度丢失、不稳定等)
技术选型与架构设计
前端方案
针对IE8兼容性问题,我们采用"渐进增强"策略:
- 现代浏览器:使用基于Vue3的现代上传组件
- IE8:回退到基于Flash的上传方案(作为备选)
// 文件上传组件入口检测functiondetectUploadMethod(){if(window.File&&window.FileReader&&window.FileList&&window.Blob){return'modern';// 使用HTML5上传}elseif(window.ActiveXObject&&newActiveXObject('ShockwaveFlash.ShockwaveFlash')){return'flash';// 使用Flash上传}else{thrownewError('不支持的浏览器环境');}}后端方案
基于.NET Core构建高性能文件传输服务,主要特点:
- 分块上传/下载
- 断点续传
- 加密传输存储
- 多存储后端支持(华为云OBS/本地存储)
核心组件实现
前端实现(Vue3组件)
// LargeFileUploader.vueimport{ref}from'vue';import{useChunkedUpload}from'./composables/useChunkedUpload';constprops=defineProps({maxFileSize:{type:Number,default:21474836480},// 20GBchunkSize:{type:Number,default:10485760},// 10MBaccept:{type:String,default:'*'},});const{files,progress,upload,pause,resume,cancel,}=useChunkedUpload({maxFileSize:props.maxFileSize,chunkSize:props.chunkSize,endpoint:'/api/upload',});后端实现(.NET Core控制器)
// FileTransferController.cs[ApiController][Route("api/[controller]")]publicclassFileTransferController:ControllerBase{privatereadonlyIFileTransferService_fileTransferService;privatereadonlyILogger_logger;publicFileTransferController(IFileTransferServicefileTransferService,ILoggerlogger){_fileTransferService=fileTransferService;_logger=logger;}[HttpPost("upload")][DisableRequestSizeLimit]publicasyncTaskUploadChunk([FromQuery]stringfileId,[FromQuery]intchunkNumber,[FromQuery]inttotalChunks,[FromQuery]stringfileName,[FromQuery]longfileSize,IFormFilechunk){try{varresult=await_fileTransferService.ProcessChunkAsync(fileId,chunkNumber,totalChunks,fileName,fileSize,chunk);returnOk(result);}catch(Exceptionex){_logger.LogError(ex,"上传分块失败");returnStatusCode(500,new{error=ex.Message});}}[HttpGet("download")]publicasyncTaskDownloadFile([FromQuery]stringfileId,[FromQuery]stringfileName){try{var(stream,contentType)=await_fileTransferService.GetFileStreamAsync(fileId,fileName);returnFile(stream,contentType,fileName);}catch(Exceptionex){_logger.LogError(ex,"下载文件失败");returnStatusCode(500,new{error=ex.Message});}}}关键技术实现
1. 断点续传实现
// FileTransferService.cspublicasyncTaskProcessChunkAsync(stringfileId,intchunkNumber,inttotalChunks,stringfileName,longfileSize,IFormFilechunk){// 检查并创建临时目录vartempDir=Path.Combine(Path.GetTempPath(),"uploads",fileId);Directory.CreateDirectory(tempDir);// 保存分块文件varchunkPath=Path.Combine(tempDir,$"{chunkNumber}.part");awaitusingvarstream=newFileStream(chunkPath,FileMode.Create);awaitchunk.CopyToAsync(stream);// 检查是否所有分块都已上传varuploadedChunks=Directory.GetFiles(tempDir).Length;if(uploadedChunks==totalChunks){// 合并文件varfinalPath=awaitMergeChunksAsync(tempDir,fileName,totalChunks);// 加密存储await_storageService.StoreEncryptedFileAsync(finalPath,fileId);returnnewChunkUploadResult{Completed=true,FileId=fileId,Progress=100};}returnnewChunkUploadResult{Completed=false,FileId=fileId,Progress=(int)((uploadedChunks/(double)totalChunks)*100)};}2. 文件夹结构保留实现
// 前端文件夹上传处理asyncfunctionuploadFolder(folder,basePath=''){constentries=awaitreadDirectoryEntries(folder);for(constentryofentries){if(entry.isFile){constfile=awaitgetAsFile(entry);constrelativePath=basePath+entry.name;awaituploadFile(file,{relativePath,isFolderUpload:true});}elseif(entry.isDirectory){awaituploadFolder(entry,`${basePath}${entry.name}/`);}}}// 后端文件夹结构重建publicasyncTaskReconstructFolderStructure(string sessionId,string rootPath){varfolderInfo=await_dbContext.UploadSessions.Where(s=>s.SessionId==sessionId).Select(s=>s.FolderStructure).FirstOrDefaultAsync();if(string.IsNullOrEmpty(folderInfo))return;varstructure=JsonConvert.DeserializeObject(folderInfo);awaitRecreateFolders(rootPath,structure);}privateasyncTaskRecreateFolders(string currentPath,FolderNode node){varfullPath=Path.Combine(currentPath,node.Name);Directory.CreateDirectory(fullPath);foreach(varchildinnode.Children){if(child.IsDirectory){awaitRecreateFolders(fullPath,child);}else{awaitMoveFileToDestination(child.FileId,fullPath,child.Name);}}}3. 多浏览器兼容方案
// 浏览器兼容层exportfunctiongetUploader(){if(supportsModernUpload()){returnnewModernUploader();}elseif(supportsFlash()){returnnewFlashUploader();}else{thrownewError('Unsupported browser');}}functionsupportsModernUpload(){return(window.File&&window.FileReader&&window.FileList&&window.Blob&&'slice'inFile.prototype);}functionsupportsFlash(){try{return!!newActiveXObject('ShockwaveFlash.ShockwaveFlash');}catch(e){return(navigator.mimeTypes&&navigator.mimeTypes['application/x-shockwave-flash']!==undefined);}}部署架构
客户端浏览器 │ ├─ IE8/国产浏览器 → Flash上传网关 → 文件传输服务 │ └─ 现代浏览器 → 直接连接 → 文件传输服务 │ ├─ 文件元数据 → 数据库集群 │ ├─ 文件内容 → 华为云OBS/本地存储 │ └─ 加密密钥 → 密钥管理服务性能优化措施
- 分块并发上传:前端同时上传多个分块,提高传输速度
- 内存优化:后端流式处理,避免大文件内存占用
- 进度持久化:本地存储上传进度,防止页面刷新丢失
- 智能重试机制:网络波动时自动重试失败的分块
- 传输压缩:可选启用LZ4压缩减少传输量
安全措施
- 传输加密:支持SM4/AES加密传输
- 存储加密:文件落地前自动加密
- 完整性校验:每个分块MD5校验
- 访问控制:基于JWT的细粒度权限控制
- 审计日志:记录所有文件传输操作
项目进度规划
- 第一阶段(2周):核心上传下载功能实现
- 第二阶段(1周):文件夹结构保留功能
- 第三阶段(1周):IE8和国产浏览器兼容
- 第四阶段(1周):加密传输和存储集成
- 第五阶段(1周):测试和性能优化
预期成果
- 完全满足客户需求的文件传输解决方案
- 解决现有WebUploader方案的稳定性问题
- 提供良好的用户体验和可靠的数据传输
- 模块化设计便于未来扩展和维护
- 完整的技术文档和API参考
这套方案将彻底解决公司当前面临的大文件传输难题,同时为未来的类似需求提供了可靠的技术基础。
设置框架
目标框架选择8.0
IDE使用VS2022
编译项目
修改测试端口
修改项目测试端口
访问测试页面
NOSQL
NOSQL无需任何配置可直接访问页面进行测试
创建数据库
配置数据库连接信息
检查数据库配置
访问页面进行测试
效果预览
文件上传
文件刷新续传
支持离线保存文件进度,在关闭浏览器,刷新浏览器后进行不丢失,仍然能够继续上传
文件夹上传
支持上传文件夹并保留层级结构,同样支持进度信息离线保存,刷新页面,关闭页面,重启系统不丢失上传进度。
下载完整示例
已经上传到gitee了,可以直接下载
下载完整示例