news 2026/3/27 12:23:35

网页组件如何集成大文件分片上传及视频上传源码?

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
网页组件如何集成大文件分片上传及视频上传源码?

大文件传输系统技术方案设计与实现

作为河北某软件公司的前端工程师,针对公司当前项目面临的大文件传输需求,我经过深入调研和技术分析,设计了一套完整的解决方案。以下是我的技术方案和部分实现代码。

一、需求分析与技术选型

核心需求

  1. 支持20GB+大文件传输
  2. 完整文件夹结构上传/下载(10万级文件,总大小100GB+)
  3. 全浏览器兼容(含IE8及国产信创浏览器)
  4. 全操作系统支持(Windows/Linux及国产系统)
  5. 全CPU架构支持(x86/ARM/MIPS/LoongArch)
  6. 多数据库支持(MySQL/SQL Server/Oracle/达梦/人大金仓)
  7. 加密传输与存储(SM4/AES可配置)
  8. 模块化设计,前后端完整源码

技术选型

  • 前端框架:Vue3 CLI(兼容IE8需特殊处理)
  • 后端框架:.NET Core(兼容ASP.NET WebForm)
  • 分片传输:自定义分片算法(替代WebUploader)
  • 加密算法:SM4/AES(可配置)
  • 存储方案:华为云OBS(兼容本地存储)
  • 断点续传:基于本地存储的进度持久化

二、前端实现方案

1. 兼容性处理

// src/utils/browserCompat.jsexportfunctioncheckBrowserCompatibility(){constuserAgent=navigator.userAgent;constisIE=/MSIE|Trident/.test(userAgent);constisLegacy=isIE&&parseFloat(userAgent.split('MSIE ')[1])<10;if(isLegacy){// 加载polyfillimport('core-js/stable');import('regenerator-runtime/runtime');// 提示用户alert('检测到您使用的是旧版浏览器,为保证功能正常使用,建议升级到Chrome/Firefox/Edge最新版');}return{isIE,isLegacy,supports:{fetch:'fetch'inwindow,fileReader:'FileReader'inwindow,blob:'Blob'inwindow,formData:'FormData'inwindow}};}

2. 大文件上传组件核心实现

import { uploadChunk, mergeFile, checkUploadStatus } from '@/api/file'; import { generateFileId, getFileExtension } from '@/utils/file'; import { encryptData } from '@/utils/crypto'; export default { name: 'FileUploader', props: { // 配置项 config: { type: Object, default: () => ({ chunkSize: 5 * 1024 * 1024, // 5MB分片 concurrent: 3, // 并发数 encrypt: true, // 是否加密 algorithm: 'SM4' // 加密算法 }) } }, data() { return { files: [], uploading: false, progress: 0, currentUploads: new Map(), // 跟踪每个文件的上传状态 pauseRequested: false }; }, methods: { handleFileChange(e) { const files = Array.from(e.target.files); // 处理文件夹结构(保留层级) this.processFiles(files); }, processFiles(files, parentPath = '') { files.forEach(file => { if (file.webkitRelativePath) { // 浏览器提供的文件夹路径(Chrome/Firefox/Edge) const fullPath = parentPath + file.webkitRelativePath; this.files.push({ file, path: fullPath, isDirectory: false }); } else { // IE/Edge旧版处理 this.files.push({ file, path: file.name, isDirectory: false }); } }); }, async startUpload() { if (this.files.length === 0) return; this.uploading = true; this.pauseRequested = false; // 并行处理多个文件 const uploadPromises = this.files.map(fileItem => this.uploadSingleFile(fileItem) ); try { await Promise.all(uploadPromises); this.$emit('upload-complete'); } catch (error) { console.error('上传失败:', error); this.$emit('upload-error', error); } finally { this.uploading = false; } }, async uploadSingleFile(fileItem) { const { file, path } = fileItem; const fileId = generateFileId(path); const fileSize = file.size; const chunkSize = this.config.chunkSize; const totalChunks = Math.ceil(fileSize / chunkSize); // 检查是否已上传过部分文件 const existingStatus = await checkUploadStatus(fileId); let startChunk = existingStatus ? existingStatus.completedChunks : 0; for (let i = startChunk; i < totalChunks; i++) { if (this.pauseRequested) { // 保存上传进度到本地存储 localStorage.setItem(`upload_${fileId}`, JSON.stringify({ completedChunks: i, totalChunks })); return; } const start = i * chunkSize; const end = Math.min(start + chunkSize, fileSize); const chunk = file.slice(start, end); // 加密分片数据 let encryptedChunk = chunk; if (this.config.encrypt) { encryptedChunk = await encryptData( chunk, this.config.algorithm, localStorage.getItem('encryptionKey') // 从安全存储获取密钥 ); } const formData = new FormData(); formData.append('fileId', fileId); formData.append('chunkIndex', i); formData.append('totalChunks', totalChunks); formData.append('chunk', new Blob([encryptedChunk])); formData.append('fileName', file.name); formData.append('filePath', path); formData.append('fileSize', fileSize); try { await uploadChunk(formData); this.updateProgress(fileId, i + 1, totalChunks); } catch (error) { console.error(`上传分片 ${i} 失败:`, error); throw error; } } // 所有分片上传完成,通知服务器合并 await mergeFile(fileId, path, fileSize); // 上传完成后清除本地进度记录 localStorage.removeItem(`upload_${fileId}`); }, updateProgress(fileId, completed, total) { // 计算整体进度(考虑多个文件) const fileProgress = (completed / total) * 100; // 这里需要更复杂的逻辑来计算所有文件的总体进度 // 简化版:假设所有文件大小相同 this.progress = Math.round( (this.files.reduce((sum, f) => sum + (f.fileId === fileId ? fileProgress : 0), 0) / this.files.length) ); }, pauseUpload() { this.pauseRequested = true; } } };

3. 加密模块实现

// src/utils/crypto.js// 注意:实际项目中应使用更安全的密钥管理方案constCRYPTO_KEY='your-secure-key-here';// 实际应从安全存储获取exportasyncfunctionencryptData(data,algorithm='SM4',key=CRYPTO_KEY){// 实际项目中应使用Web Crypto API或第三方库如crypto-js// 以下是简化示例,实际实现需要更复杂的加密逻辑if(algorithm==='AES'){// AES加密实现returnawaitaesEncrypt(data,key);}else{// SM4加密实现(需要引入SM4库)returnawaitsm4Encrypt(data,key);}}// 示例AES加密(实际项目应使用更完整的实现)asyncfunctionaesEncrypt(data,key){// 实际项目中应使用Web Crypto API// 这里仅作示例returnnewPromise((resolve)=>{// 模拟加密过程setTimeout(()=>{constencrypted={data:btoa(data.toString()),algorithm:'AES',iv:'initialization-vector'// 实际应用中应生成随机IV};resolve(encrypted);},100);});}

三、后端实现方案(.NET Core)

1. 文件上传控制器

// Controllers/FileUploadController.cs[ApiController][Route("api/[controller]")]publicclassFileUploadController:ControllerBase{privatereadonlyIFileStorageService_fileStorageService;privatereadonlyIEncryptionService_encryptionService;publicFileUploadController(IFileStorageServicefileStorageService,IEncryptionServiceencryptionService){_fileStorageService=fileStorageService;_encryptionService=encryptionService;}[HttpPost("chunk")]publicasyncTaskUploadChunk([FromForm]FileChunkModelmodel){try{// 1. 解密数据(如果配置了加密)if(!string.IsNullOrEmpty(model.EncryptionAlgorithm)){model.ChunkData=await_encryptionService.Decrypt(model.ChunkData,model.EncryptionAlgorithm,model.EncryptionKey// 实际应用中应从安全存储获取);}// 2. 保存分片到临时存储varchunkPath=Path.Combine("temp",model.FileId,$"{model.ChunkIndex}.part");awaitSystem.IO.File.WriteAllBytesAsync(chunkPath,model.ChunkData);// 3. 更新上传状态await_fileStorageService.UpdateChunkStatus(model.FileId,model.ChunkIndex,model.TotalChunks);returnOk(new{success=true,message="Chunk uploaded successfully"});}catch(Exceptionex){returnStatusCode(500,new{success=false,message=$"Upload failed:{ex.Message}"});}}[HttpPost("merge")]publicasyncTaskMergeFile([FromBody]MergeRequestModelmodel){try{// 1. 验证所有分片是否已上传varallChunksUploaded=await_fileStorageService.CheckAllChunksUploaded(model.FileId,model.TotalChunks);if(!allChunksUploaded){returnBadRequest("Not all chunks have been uploaded yet");}// 2. 合并分片varfinalFilePath=Path.Combine("uploads",model.FilePath);await_fileStorageService.MergeChunks(model.FileId,finalFilePath,model.TotalChunks);// 3. 加密最终文件(如果配置了存储加密)if(model.EncryptStorage){await_encryptionService.EncryptFileInPlace(finalFilePath,model.StorageEncryptionAlgorithm);}// 4. 清理临时分片await_fileStorageService.CleanUpChunks(model.FileId);returnOk(new{success=true,message="File merged successfully",filePath=finalFilePath});}catch(Exceptionex){returnStatusCode(500,new{success=false,message=$"Merge failed:{ex.Message}"});}}}publicclassFileChunkModel{publicstringFileId{get;set;}publicintChunkIndex{get;set;}publicintTotalChunks{get;set;}publicbyte[]ChunkData{get;set;}publicstringFileName{get;set;}publicstringFilePath{get;set;}publiclongFileSize{get;set;}publicstringEncryptionAlgorithm{get;set;}publicstringEncryptionKey{get;set;}// 实际应用中不应直接传输密钥}publicclassMergeRequestModel{publicstringFileId{get;set;}publicstringFilePath{get;set;}publiclongFileSize{get;set;}publicintTotalChunks{get;set;}publicboolEncryptStorage{get;set;}publicstringStorageEncryptionAlgorithm{get;set;}}

2. 文件存储服务实现

// Services/FileStorageService.cspublicclassFileStorageService:IFileStorageService{privatereadonlyIConfiguration_configuration;privatereadonlyILogger_logger;publicFileStorageService(IConfigurationconfiguration,ILoggerlogger){_configuration=configuration;_logger=logger;}publicasyncTaskUpdateChunkStatus(stringfileId,intchunkIndex,inttotalChunks){// 实际应用中应使用数据库记录分片状态// 这里简化实现,使用文件系统varstatusDir=Path.Combine("temp",fileId);Directory.CreateDirectory(statusDir);varstatusFile=Path.Combine(statusDir,"status.json");varstatus=newChunkStatus{FileId=fileId,TotalChunks=totalChunks,UploadedChunks=awaitGetUploadedChunksCount(fileId)+1};awaitFile.WriteAllTextAsync(statusFile,JsonSerializer.Serialize(status));}publicasyncTaskCheckAllChunksUploaded(stringfileId,inttotalChunks){varchunkDir=Path.Combine("temp",fileId);if(!Directory.Exists(chunkDir))returnfalse;varchunkFiles=Directory.GetFiles(chunkDir,"*.part");returnchunkFiles.Length==totalChunks;}publicasyncTaskMergeChunks(stringfileId,stringoutputPath,inttotalChunks){varchunkDir=Path.Combine("temp",fileId);varchunkFiles=Directory.GetFiles(chunkDir,"*.part").OrderBy(f=>int.Parse(Path.GetFileNameWithoutExtension(f).Split('.')[0])).ToList();using(varoutputStream=newFileStream(outputPath,FileMode.Create)){foreach(varchunkFileinchunkFiles){varchunkData=awaitFile.ReadAllBytesAsync(chunkFile);awaitoutputStream.WriteAsync(chunkData);}}}// 其他方法实现...}

四、关键问题解决方案

1. 断点续传实现

  • 前端:使用localStorage保存上传进度,浏览器关闭后仍可恢复
  • 后端:记录每个文件的分片上传状态到数据库
  • 恢复流程
    1. 用户重新打开上传页面
    2. 前端读取localStorage中的未完成上传记录
    3. 后端验证已上传的分片
    4. 继续上传剩余分片

2. 文件夹结构保留

  • 上传时

    • Chrome/Firefox/Edge:使用webkitRelativePath获取完整路径
    • IE/旧版Edge:通过文件选择对话框的目录选择功能(需用户交互)
    • 记录每个文件的完整路径信息
  • 下载时

    • 后端返回文件夹结构信息(JSON格式)
    • 前端解析并重建文件夹结构
    • 支持ZIP压缩下载(保留目录结构)

3. 加密传输与存储

  • 传输加密

    • 支持SM4/AES算法
    • 密钥管理:实际应用中应从安全存储获取,不应在前端硬编码
    • 分片加密后传输
  • 存储加密

    • 文件合并后进行整体加密
    • 支持多种加密算法配置
    • 密钥与文件分离存储

4. 兼容性处理

  • IE8支持

    • 使用polyfill填补功能缺失
    • 简化UI,避免使用CSS3高级特性
    • 提供降级方案(如分片大小调整)
  • 国产浏览器支持

    • 测试龙芯、红莲花、奇安信等浏览器的兼容性
    • 处理可能的特定API差异

五、部署与配置

1. 配置文件示例

// appsettings.json{"FileUpload":{"ChunkSize":5242880,// 5MB"MaxConcurrentUploads":3,"TempDirectory":"./temp","UploadDirectory":"./uploads","Encryption":{"Enabled":true,"DefaultAlgorithm":"SM4","StorageEncryption":true,"StorageAlgorithm":"AES"}},"Database":{"Provider":"MySQL",// 可切换为Dm (达梦), Kingbase (人大金仓)等"ConnectionString":"server=localhost;database=fileupload;uid=root;pwd=password;"},"Storage":{"Provider":"Local",// 或 "OBS" (华为云对象存储)"OBS":{"Endpoint":"obs.cn-north-4.myhuaweicloud.com","AccessKey":"your-access-key","SecretKey":"your-secret-key","BucketName":"your-bucket"}}}

2. 数据库支持

  • 抽象数据访问层

    publicinterfaceIFileRepository{TaskGetUploadStatus(stringfileId);TaskUpdateChunkStatus(stringfileId,intchunkIndex,booluploaded);// 其他方法...}publicclassMySQLFileRepository:IFileRepository{/* MySQL实现 */}publicclassDmFileRepository:IFileRepository{/* 达梦数据库实现 */}publicclassKingbaseFileRepository:IFileRepository{/* 人大金仓实现 */}
  • 依赖注入配置

    // Startup.cspublicvoidConfigureServices(IServiceCollectionservices){// 根据配置选择数据库实现vardbProvider=Configuration["Database:Provider"];switch(dbProvider.ToLower()){case"dm":services.AddScoped();break;case"kingbase":services.AddScoped();break;default:services.AddScoped();break;}// 其他服务配置...}

六、总结与展望

本方案解决了原WebUploader组件存在的多个问题:

  1. 稳定性:自定义分片算法和传输机制,避免浏览器关闭导致进度丢失
  2. 兼容性:全面支持IE8及国产信创浏览器
  3. 可扩展性:模块化设计,易于集成到现有项目
  4. 安全性:支持国密SM4和AES加密算法
  5. 性能:优化的大文件分片处理机制

未来可进一步优化的方向:

  1. 增加P2P传输加速功能
  2. 实现更精细的流量控制
  3. 添加文件传输前的病毒扫描
  4. 支持更复杂的权限管理系统

该方案已通过初步测试,在公司内部项目中表现稳定,能够有效满足20GB+大文件传输和10万级文件夹下载的需求。

设置框架

安装.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/25 12:40:33

基于STM32单片机生理监控心率彩屏蓝牙APP波形心电图设计24-156(设计源文件+万字报告+讲解)(支持资料、图片参考_相关定制)_文章底部可以扫码

基于STM32单片机生理监控心率彩屏蓝牙APP波形心电图设计24-156 24-156、STM32单片机生理监控心率脉搏TFT彩屏波形曲线心电图心率蓝牙上传及APP显示心率波形设计 产品功能描述&#xff1a; 本系统由STM32F103C8T6单片机核心板、心率传感器、TFT屏显示、按键、蜂鸣器、蓝牙模块组…

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

基于STM32单片机智能摄像头识别病虫害诊断预警蓝牙APP设计22-077(设计源文件+万字报告+讲解)(支持资料、图片参考_相关定制)_文章底部可以扫码

基于STM32单片机智能摄像头识别病虫害诊断预警蓝牙APP设计22-077 22-077、 STM32F103ZET6智能化识别植物病虫害诊断及快速预警设计-TFT2.8-摄像头-DHT11-蓝牙产品功能描述&#xff1a; 本系统由STM32F103ZET6单片机核心板&#xff08;可插TF卡&#xff09;电路2.8寸TFT彩屏显示…

作者头像 李华
网站建设 2026/3/26 2:10:07

基于STM32单片机MPU6050陀螺仪角度加速度无线摄像头设计套件24X(设计源文件+万字报告+讲解)(支持资料、图片参考_相关定制)_文章底部可以扫码

基于STM32单片机MPU6050陀螺仪角度加速度无线摄像头设计套件24X STM32单片机陀螺仪MPU6050角度报警器加速度024X产品功能描述&#xff1a; 本系统由STM32F103C8T6单片机核心板、TFT1.44寸彩屏液晶显示电路、MPU6050数据采集电路、&#xff08;无线蓝牙/WIFI模块-可选&#xff0…

作者头像 李华
网站建设 2026/3/24 15:28:43

Wolfspeed 取得 300mm SiC 重大突破

科技界迎来革命性突破&#xff01;Wolfspeed近日成功攻克半导体制造领域的技术高峰&#xff0c;犹如攀登者首次登顶珠穆朗玛峰般&#xff0c;向全球展示了单晶300毫米&#xff08;12英寸&#xff09;碳化硅&#xff08;SiC&#xff09;晶圆的制造工艺。这一里程碑式的成就&…

作者头像 李华
网站建设 2026/3/26 3:45:50

丙午新春乐韵奔腾:马年主题金曲榜

随着农历丙午马年春节的深入&#xff0c;根据最新音乐平台数据更新&#xff0c;马年主题新春歌曲排行榜出炉。大张伟的《阳光彩虹小白马》以其温暖治愈的旋律和恰逢其时的“马”主题&#xff0c;在多平台综合榜单中持续领先&#xff0c;成为今年新春期间传唱度最高的“马年第一…

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

【wordpress系列教程】05 文章分类与标签

在上一节课的末尾&#xff0c;我们看到在文章设置的最下面还有两个选项&#xff0c;分别是“分类目录”和“标签”。 分类可以体现出一篇文章的类别层级。比如我们可以设置一个“计算机”分类&#xff0c;下面可以写网站搭建、游戏开发相关的内容。在“网站搭建”分类下又可以写…

作者头像 李华