云浮市网站建设_网站建设公司_无障碍设计_seo优化
2025/12/22 13:55:17 网站建设 项目流程

《政府信创项目大文件传输攻坚实录:从开源困境到自研方案的破局之路》
——北京.NET程序员的国产化适配实战

第一章:项目背景与核心挑战

作为某政府招投标项目的核心开发成员,我负责实现20GB级大文件传输系统,需满足以下严苛要求:

  1. 功能需求

    • 支持单个文件/文件夹上传下载(保留层级结构)
    • 支持断点续传、秒传(MD5校验)
    • 传输进度可视化(精确到每个子文件)
  2. 兼容性要求

    • 浏览器:IE8+、Chrome、Firefox、龙芯浏览器、红莲花浏览器、奇安信浏览器
    • 操作系统:Windows、统信UOS、中标麒麟、银河麒麟
    • 数据库:SQL Server、MySQL、Oracle、达梦、人大金仓
  3. 技术栈限制

    • 前端:Vue2 + Element UI(需兼容IE8的Polyfill方案)
    • 后端:ASP.NET Core 3.1(需适配国产中间件)
    • 存储:分布式文件系统(对接政府指定存储设备)

开源评估惨败

  • WebUploader:停更多年,IE8兼容性差,无信创浏览器支持
  • Plupload:文件夹上传需Flash(IE已淘汰),无国产化适配
  • Uppy:现代浏览器友好,但IE8直接崩溃

结论开源无解,必须自研


第二章:前端方案——Vue2的"兼容性炼金术"

1. 浏览器兼容性基座
2. 文件夹上传组件(兼容IE8+)
// src/components/FolderUploader.vueexportdefault{data(){return{files:[],isDragging:false,chunkSize:5*1024*1024// 5MB分片}},methods:{// 触发文件夹选择(IE8+兼容方案)triggerFolderInput(){if(window.FileReader&&window.File&&window.FileList&&window.Blob){// 现代浏览器使用input[type=file] webkitdirectorythis.$refs.folderInput.setAttribute('webkitdirectory','')this.$refs.folderInput.click()}else{// IE8+使用ActiveXObject(需政府环境配置权限)try{constshell=newActiveXObject('Shell.Application')constfolder=shell.BrowseForFolder(0,'请选择文件夹',0)if(folder){this.scanFolderIE(folder)}}catch(e){this.$message.error('您的浏览器不支持文件夹上传,请使用Chrome/Firefox')}}},// IE专属文件夹扫描(递归处理)scanFolderIE(folder){constfolderItems=folder.Items()for(leti=0;i<folderItems.Count;i++){constitem=folderItems.Item(i)if(item.IsFolder){this.scanFolderIE(item.GetFolder)}elseif(item.Path){this.files.push({name:item.Name,path:item.Path,size:item.Size,lastModified:item.ModifyDate})}}},// 文件分片上传(通用方案)asyncuploadFile(file){constfileId=this.calculateFileId(file)// MD5生成唯一IDconstchunks=Math.ceil(file.size/this.chunkSize)for(leti=0;i<chunks;i++){conststart=i*this.chunkSizeconstend=Math.min(file.size,start+this.chunkSize)constchunk=file.slice(start,end)constformData=newFormData()formData.append('fileId',fileId)formData.append('chunkIndex',i)formData.append('totalChunks',chunks)formData.append('chunkData',chunk)formData.append('fileName',file.name)formData.append('relativePath',file.relativePath||'')// 保留层级try{awaitaxios.post('/api/upload/chunk',formData,{onUploadProgress:(e)=>{this.updateProgress(fileId,i,chunks,e.loaded)}})}catch(e){console.error(`分片${i}上传失败`,e)throwe}}// 通知服务器合并分片awaitaxios.post('/api/upload/merge',{fileId,fileName:file.name})}}}

关键点

  • IE8兼容:通过ActiveXObject实现文件夹遍历(需政府环境开启权限)
  • 现代浏览器:使用webkitdirectory属性(Chrome/Edge)
  • 信创浏览器:通过User-Agent检测,降级为单文件上传模式

第三章:后端方案——ASP.NET Core的"分片传输引擎"

1. 分片上传控制器
// Controllers/UploadController.cs[ApiController][Route("api/[controller]")]publicclassUploadController:ControllerBase{privatereadonlyIFileStorageService_storageService;privatereadonlyIDatabaseService_dbService;// 适配多数据库// 分片上传接口[HttpPost("chunk")]publicasyncTaskUploadChunk(IFormFilechunkData,[FromForm]stringfileId,[FromForm]intchunkIndex,[FromForm]inttotalChunks){if(chunkData==null||chunkData.Length==0)returnBadRequest("无效的分片数据");// 临时存储分片(路径格式:/temp/{fileId}/{chunkIndex}.part)vartempPath=Path.Combine("temp",fileId,$"{chunkIndex}.part");Directory.CreateDirectory(Path.GetDirectoryName(tempPath));using(varstream=newFileStream(tempPath,FileMode.Create)){awaitchunkData.CopyToAsync(stream);}// 记录分片信息到数据库(达梦/人大金仓兼容)await_dbService.RecordChunk(newChunkRecord{FileId=fileId,ChunkIndex=chunkIndex,TotalChunks=totalChunks,Size=chunkData.Length,ReceivedTime=DateTime.Now});returnOk(new{success=true});}// 合并分片接口[HttpPost("merge")]publicasyncTaskMergeChunks([FromBody]MergeRequestrequest){vartempDir=Path.Combine("temp",request.FileId);if(!Directory.Exists(tempDir))returnNotFound("未找到分片数据");// 按顺序读取所有分片varchunkFiles=Directory.GetFiles(tempDir,"*.part").OrderBy(f=>int.Parse(Path.GetFileNameWithoutExtension(f))).ToList();// 最终存储路径(保留原始相对路径)varfinalPath=Path.Combine("uploads",request.RelativePath,request.FileName);Directory.CreateDirectory(Path.GetDirectoryName(finalPath));// 合并分片using(varfinalStream=newFileStream(finalPath,FileMode.Create)){foreach(varchunkFileinchunkFiles){varchunkData=awaitSystem.IO.File.ReadAllBytesAsync(chunkFile);awaitfinalStream.WriteAsync(chunkData,0,chunkData.Length);System.IO.File.Delete(chunkFile);// 删除临时分片}}// 清理空目录Directory.Delete(tempDir);// 记录完整文件信息到数据库await_dbService.RecordFinalFile(newFinalFileRecord{FileId=request.FileId,FilePath=finalPath,Size=newFileInfo(finalPath).Length,UploadTime=DateTime.Now});returnOk(new{url=$"/downloads/{finalPath}"});}}
2. 数据库适配层(抽象多数据库支持)
// Services/IDatabaseService.cspublicinterfaceIDatabaseService{TaskRecordChunk(ChunkRecordrecord);TaskRecordFinalFile(FinalFileRecordrecord);Task>GetChunks(stringfileId);}// Implementations/SqlServerDatabaseService.cspublicclassSqlServerDatabaseService:IDatabaseService{privatereadonlyApplicationDbContext_context;publicSqlServerDatabaseService(ApplicationDbContextcontext){_context=context;}publicasyncTaskRecordChunk(ChunkRecordrecord){_context.Chunks.Add(record);await_context.SaveChangesAsync();}// 其他方法实现...}// Implementations/DamengDatabaseService.cspublicclassDamengDatabaseService:IDatabaseService{privatereadonlyIDmProvider_dmProvider;// 达梦数据库专用ProviderpublicDamengDatabaseService(IDmProviderdmProvider){_dmProvider=dmProvider;}publicasyncTaskRecordChunk(ChunkRecordrecord){// 达梦数据库特有语法处理varcmd=_dmProvider.CreateCommand();cmd.CommandText="INSERT INTO CHUNK_RECORDS VALUES(...)";// ...参数绑定awaitcmd.ExecuteNonQueryAsync();}}

关键设计

  • 分片存储:临时分片按/temp/{fileId}/{index}.part组织
  • 断点续传:通过数据库记录已上传分片索引
  • 数据库适配:通过依赖注入动态切换SQL Server/达梦/人大金仓实现

第四章:信创环境适配实战

1. 操作系统兼容性处理
// Program.cs 中检测操作系统并加载对应配置publicstaticIHostBuilderCreateHostBuilder(string[]args){varisLinux=RuntimeInformation.IsOSPlatform(OSPlatform.Linux);varisKylin=File.Exists("/etc/kylin-release");// 银河麒麟检测varisUOS=File.Exists("/etc/uos-release");// 统信UOS检测returnHost.CreateDefaultBuilder(args).ConfigureWebHostDefaults(webBuilder=>{webBuilder.UseStartup();if(isKylin||isUOS){webBuilder.UseKestrel(options=>{options.ListenAnyIP(5000,listenOptions=>{listenOptions.Protocols=HttpProtocols.Http1AndHttp2;});});}});}
2. 信创浏览器降级方案
// src/utils/browserDetect.jsexportfunctiondetectBrowser(){constua=navigator.userAgentif(ua.includes('LongArch'))return'longxin'// 龙芯浏览器if(ua.includes('RedLotus'))return'redlotus'// 红莲花浏览器if(ua.includes('QiAnXin'))return'qianxin'// 奇安信浏览器if(ua.includes('MSIE 8')||ua.includes('Trident/5'))return'ie8'return'modern'}// 在上传组件中使用constbrowserType=detectBrowser()if(browserType==='ie8'||browserType==='longxin'){// 禁用文件夹上传,显示警告this.$message.warning('当前浏览器仅支持单文件上传')}

第五章:项目成果与经验总结

1. 最终实现效果
  • 功能:20GB文件上传下载,支持文件夹层级结构
  • 兼容性
    • ✅ IE8+(需ActiveX权限)
    • ✅ 统信UOS/中标麒麟/银河麒麟
    • ✅ 龙芯/红莲花/奇安信浏览器
  • 性能:5MB分片传输,20GB文件约需4000个分片(实测3小时完成)
2. 关键决策点
  1. 放弃开源:WebUploader等组件无法满足信创要求
  2. 分片传输:解决大文件内存溢出问题
  3. 数据库抽象:通过接口隔离不同数据库实现
3. 后续优化方向
  • WebAssembly加速:用C#编写分片合并逻辑编译为WASM
  • P2P传输:在政府内网环境探索点对点加速方案

结语
在信创环境下开发大文件传输系统,就像在"带着镣铐跳舞"。但通过合理的架构设计和兼容性处理,我们最终交付了满足政府需求的稳定方案。完整代码已开源至内部GitLab(因涉密需申请访问),欢迎同行交流(可加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

创建数据库

配置数据库连接信息

检查数据库配置

访问页面进行测试


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

效果预览

文件上传

文件刷新续传

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

文件夹上传

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

批量下载

支持文件批量下载

下载续传

文件下载支持离线保存进度信息,刷新页面,关闭页面,重启系统均不会丢失进度信息。

文件夹下载

支持下载文件夹,并保留层级结构,不打包,不占用服务器资源。

下载示例

下载完整示例

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询