医院PACS系统如何用WebUploader+PHP解决DICOM影像分片传输卡顿?
天津XX软件公司大文件传输系统前端技术方案(第一人称视角)
一、技术选型与架构设计
作为前端负责人,我主导了基于Vue3 + TypeScript的模块化架构设计,核心解决以下痛点:
- 浏览器兼容性:通过分层适配策略覆盖IE8+及信创浏览器
- 大文件稳定性:实现浏览器标签页关闭后仍能恢复的持久化断点续传
- 跨平台兼容:统一ARM/MIPS/x86架构下的文件处理逻辑
- 国产化适配:深度集成华为云OBS的信创版本SDK
渲染错误: Mermaid 渲染失败: Parse error on line 8: ...ill] --> G[ActiveX控件(备用)] H[信创浏览 -----------------------^ Expecting 'SQE', 'DOUBLECIRCLEEND', 'PE', '-)', 'STADIUMEND', 'SUBROUTINEEND', 'PIPE', 'CYLINDEREND', 'DIAMOND_STOP', 'TAGEND', 'TRAPEND', 'INVTRAPEND', 'UNICODE_TEXT', 'TEXT', 'TAGSTART', got 'PS'
二、核心模块实现
1. 跨浏览器文件选择器(Vue3组件)
import { defineComponent, ref, onMounted } from 'vue'; import { BrowserDetector } from './browser-detector'; export default defineComponent({ setup() { const standardInput = ref<HTMLInputElement>(); const isLegacyBrowser = BrowserDetector.isIE8(); const isTrustedBrowser = BrowserDetector.isTrustedBrowser(); const handleStandardFileChange = (e: Event) => { const files = (e.target as HTMLInputElement).files; if (files) emitFiles(Array.from(files)); }; // 暴露接口给后端调用 window.selectFiles = (callback: (files: File[]) => void) => { // 实现跨窗口文件选择逻辑 }; return { standardInput, isLegacyBrowser }; } }); 2. 持久化断点续传引擎
// transfer-engine.tsclassPersistentUploader{privatestaticINSTANCE: PersistentUploader;private uploadRecords: Map =newMap();// 单例模式确保全局唯一publicstaticgetInstance(): PersistentUploader {if(!this.INSTANCE){this.INSTANCE=newPersistentUploader();// 初始化时恢复未完成传输 window.addEventListener('beforeunload',()=>this.saveAllRecords());}returnthis.INSTANCE;}// 使用IndexedDB存储传输记录(IE8降级为localStorage)privateasyncgetStorage():Promise{if(BrowserDetector.supportsIndexedDB()){returnnewIndexedDBStorage('file-transfer-db');}returnnewLocalStorageAdapter();}publicasyncuploadFile(file: File, config: UploadConfig):Promise{const fileId =this.generateFileId(file);const storage =awaitthis.getStorage();const record =await storage.get(fileId)||{ fileId, chunks: Math.ceil(file.size / config.chunkSize), completed:0, algorithm: config.algorithm };const task =newUploadTask(file, record, config);this.uploadRecords.set(fileId, record);// 注册恢复处理器 task.on('progress',()=>this.saveRecord(fileId, task.record));return task;}privateasyncsaveRecord(fileId:string, record: UploadRecord){(awaitthis.getStorage()).set(fileId, record);}}3. 信创浏览器事件桥接
// trusted-browser-adapter.js(function(){// 检测是否为信创浏览器const isTrusted =/Qianxin|Longsen|Honglian/i.test(navigator.userAgent);if(!isTrusted)return;// 建立跨域通信通道const bridge ={receiveMessage:function(data){// 处理来自信创浏览器扩展的消息if(data.type ==='FILE_SELECTED'){const event =newCustomEvent('trustedFileSelected',{detail: data.files }); window.dispatchEvent(event);}},sendMessage:function(action, payload){// 调用浏览器扩展APIif(window.trustedBrowserAPI){ window.trustedBrowserAPI.postMessage({ action, payload });}}};// 暴露给全局 window.trustedBridge = bridge;})();三、后端接口集成(.NET Core示例)
1. 文件分片上传控制器
// FileChunkController.cs[ApiController][Route("api/file-transfer")]publicclassFileChunkController:ControllerBase{privatereadonlyIFileStorageService _storageService;privatereadonlyIEncryptionService _encryptionService;[HttpPost("chunk")]publicasyncTaskUploadChunk([FromForm]IFormFile chunk,[FromForm]string fileId,[FromForm]int chunkIndex,[FromForm]string algorithm ="SM4"){// 验证分片if(chunk.Length ==0)returnBadRequest();// 解密处理(根据配置)byte[] decryptedData = algorithm switch{"SM4"=> _encryptionService.SM4Decrypt(await chunk.ToByteArray()),"AES"=> _encryptionService.AESDecrypt(await chunk.ToByteArray()), _ =>await chunk.ToByteArray()};// 存储分片(华为云OBS适配)var chunkPath =$"{fileId}/chunk-{chunkIndex}";await _storageService.SaveChunk(chunkPath, decryptedData);returnOk(new{ status ="saved", chunkIndex, nextExpectedIndex = chunkIndex +1});}}2. 数据库动态适配层
// DatabaseAdapterFactory.cspublicstaticclassDatabaseAdapterFactory{publicstaticIFileMetaRepositoryGetAdapter(string dbType){return dbType.ToLower()switch{"mysql"=>newMySqlFileMetaRepository(),"oracle"=>newOracleFileMetaRepository(),"dm"=>newDamengFileMetaRepository(),// 达梦数据库"kingbase"=>newKingbaseFileMetaRepository(),// 人大金仓 _ =>thrownewNotSupportedException($"Unsupported DB: {dbType}")};}}// 统一接口示例publicinterfaceIFileMetaRepository{TaskGetMetadata(string fileId);TaskSaveMetadata(FileMetadata metadata);}四、国产化特殊处理
1. 龙芯MIPS架构优化
// loongson-optimizer.tsexportclassLoongsonUploaderextendsBaseUploader{protected override calculateChunkSize(file: File):number{// 龙芯CPU单线程性能较弱,适当减小分片大小const isLoongson = navigator.hardwareConcurrency <4;return isLoongson ?2*1024*1024:super.calculateChunkSize(file);}protected override asyncencryptChunk(data: Blob, algorithm:string):Promise{// 使用WebCrypto API的SM4实现(需引入polyfill)if(algorithm ==='SM4'&&!crypto.subtle.supports('SM4')){returnthis.fallbackSM4Encrypt(data);// 降级到JavaScript实现}returnsuper.encryptChunk(data, algorithm);}}2. 华为云OBS信创版集成
// obs-client-adapter.jsclassOBSAdaptor{constructor(config){this.config ={...config,// 信创环境特殊配置sslVerified: config.isTrustedEnv ?false:true,region: config.region ||'cn-north-4',// 国产化操作系统需要指定SDK版本sdkVersion:isNationalOS()?'obs-sdk-national-2.2.11':'obs-sdk-2.2.11'};}asyncuploadFile(file, options){// 动态加载SDK(避免打包体积过大)if(!window.OBS){awaitthis.loadScript(this.getSdkUrl());}const obs =newOBS({access_key_id:this.config.ak,secret_access_key:this.config.sk,endpoint:this.config.endpoint,use_ssl:this.config.sslVerified,// 国产化环境需要禁用某些特性disable_features:isNationalOS()?['multi_part_upload']:[]});returnnewPromise((resolve, reject)=>{ obs.putObject({Bucket: options.bucket,Key: options.key,Body: file,ContentType: options.mimeType,// 信创环境需要特殊头部...(isNationalOS()&&{'x-obs-national-env':'true'})},(err, result)=>{ err ?reject(err):resolve(result);});});}}五、实施路线与测试策略
- 渐进式兼容测试
- IE8: 使用VirtualBox搭建Win7+IE8测试环境
- 信创浏览器: 联系厂商获取测试授权
- 国产化OS: 申请华为云鲲鹏/飞腾开发者实验室资源
- 国产化适配验证
- 达梦数据库:通过ODBC驱动实现ORM映射
- 人大金仓:使用PostgreSQL协议兼容模式
- 统信UOS:通过Deepin Wine运行旧版ActiveX控件
性能基准测试
| 测试场景 | 目标指标 | 实际结果 |
|---|---|---|
| 100GB文件上传 | <4小时 | 3h47m (鲲鹏920) |
| 10万文件下载 | 内存峰值<1GB | 856MB (飞腾2000) |
| IE8断点续传 | 100次测试0丢失 | 100/100 |
六、交付成果
- 前端组件库
- 支持Vue3的``全局组件
- 提供TypeScript类型定义文件
- 包含完整单元测试(Jest覆盖率>85%)
- 后端适配包
- .NET Core中间件(
FileTransferMiddleware) - ASP.NET WebForm兼容层(通过Handler实现)
- 华为云OBS信创版SDK封装
- .NET Core中间件(
- 部署文档
- 国产化环境部署指南
- 信创浏览器适配手册
- 跨数据库迁移脚本
该方案已通过内部POC验证,在兆芯CPU+统信UOS环境下实现:
- 23GB文件上传:稳定在120Mbps(约17分钟)
- 5万文件层级结构保留:解析时间<3秒
- IE8兼容模式:通过ActiveX实现基础功能建议立即启动信创实验室环境搭建,争取在Q2完成首个国产化项目交付。
复制组件
示例中已经包含此目录

引入组件

配置接口地址
接口地址分别对应:文件初始化,文件数据上传,文件进度,文件上传完毕,文件删除,文件夹初始化,文件夹删除,文件列表
参考:http://www.ncmem.com/doc/view.aspx?id=e1f49f3e1d4742e19135e00bd41fa3de

处理事件

启动测试

启动成功

效果

数据库

效果预览
文件上传

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

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

批量下载
支持文件批量下载

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

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