news 2026/2/24 14:06:15

HTTP协议在.NET Core大文件上传中如何优化分片传输的效率?

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
HTTP协议在.NET Core大文件上传中如何优化分片传输的效率?

.NET老哥外包项目救星:原生JS大文件上传全栈方案(IE8兼容+20G断点续传)

兄弟,作为甘肃接外包的.NET程序员,我太懂你现在的处境了——客户要20G大文件上传,还要文件夹层级保留、IE8兼容、加密传输,预算还卡得死死的。网上找的代码全是“文件上传半成品”,文件夹功能要么丢层级,要么IE8直接崩。别慌!我熬了半个月啃下的原生JS+ASP.NET WebForm全栈方案,今天全盘托出,保证你能直接给客户演示,验收时被夸“这钱花得值”!


一、方案核心(专治外包项目的“奇葩需求”)

1. 功能全覆盖(客户看了直点头)

  • 20G级大文件传输:分片上传(10MB/片),断点续传(localStorage+SQL Server双存储进度,关浏览器/重启电脑不丢)。
  • 文件夹层级保留:递归遍历文件树(前端生成相对路径),后端按/父文件夹/子文件路径存储(IE8用“伪路径+元数据”方案兜底)。
  • 加密传输+存储:传输层HTTPS+AES-256(密钥动态生成),存储层SM4(国密算法,符合客户保密要求)。
  • 非打包下载:流式传输逐个文件(几万文件也不卡),支持“文件夹结构树”展示(避免服务器内存爆炸)。
  • 全浏览器兼容:IE8(XHR2+File API补丁)→ Edge/Chrome/Firefox → macOS/Linux/CentOS(信创环境)。

2. 预算友好(0商业授权费)

  • 原生JS实现:0商业库,用crypto-js(AES)+spark-md5(文件哈希),代码直接嵌入Vue3项目。
  • 轻量级依赖:仅需Vue3、axios、crypto-js,无额外费用。
  • 本地存储适配:文件直接存服务器(E盘路径可配置),无需OSS,代码动态适配Windows/Linux。

3. 客户要的“铁证”全给齐

  • 完整源码包(前端+后端+SQL脚本),导入就能跑。
  • 部署文档(IIS配置+数据库连接+文件路径设置),手把手教客户运维。
  • 7*24小时支持:群里200+NET/前端大佬互助(QQ群:374992201),遇到坑直接甩日志截图,老炮儿带你改代码。

二、前端核心代码(Vue3兼容版,附详细注释)

1. 文件夹上传组件(兼容IE8+所有主流浏览器)

// 兼容IE8的polyfill(必须引入!) import 'es6-promise/auto'; // 补Promise import 'whatwg-fetch'; // 补fetch import Blob from 'blob-polyfill'; // 补Blob(IE8不支持slice) if (!window.console) window.console = { log: () => {}, error: () => {} }; // 补console // 依赖库(需手动安装:npm install crypto-js axios spark-md5) import CryptoJS from 'crypto-js'; import axios from 'axios'; import SparkMD5 from 'spark-md5'; export default { data() { return { uploadTasks: [], // 上传任务列表(核心数据) chunkSize: 10 * 1024 * 1024, // 10MB分片(20G文件分2000片,平衡速度与内存) aesKey: '', // AES密钥(从后端动态获取) currentTaskId: '', // 当前上传任务的ID isUploading: false // 全局上传状态锁 }; }, mounted() { this.initAesKey(); // 初始化AES密钥(首次加载时生成) this.checkResumeTasks(); // 启动时检查本地是否有未完成的任务 }, methods: { /** * 上传下一个分片(递归) * @param {Object} task 当前上传任务 */ async uploadNextChunk(task) { if (task.chunkIndex >= task.totalChunks) { // 所有分片上传完成 task.progress = 100; task.status = 'success'; task.statusText = '上传成功'; this.isUploading = false; localStorage.removeItem(`upload_${task.taskId}`); // 清除本地缓存 this.$message.success(`${task.fileName} 上传完成!`); return; } // 计算当前分片的起始和结束位置 const start = task.chunkIndex * this.chunkSize; const end = Math.min(start + this.chunkSize, task.totalSize); const chunk = task.file.slice(start, end); // IE8支持File.slice(需Blob.js补丁) // 读取分片内容并加密(原生JS实现) const reader = new FileReader(); reader.onload = (function(chunk, task) { return async function(e) { const chunkContent = e.target.result; // AES加密分片(密钥与后端一致) const encryptedChunk = CryptoJS.AES.encrypt( CryptoJS.lib.WordArray.create(chunkContent), this.aesKey, { mode: CryptoJS.mode.ECB, padding: CryptoJS.pad.Pkcs7 } ).toString(); // 构造FormData(兼容IE8) const formData = new FormData(); formData.append('taskId', task.taskId); formData.append('chunkIndex', task.chunkIndex); formData.append('totalChunks', task.totalChunks); formData.append('filePath', task.filePath); formData.append('chunk', new Blob([encryptedChunk])); try { // 调用后端上传接口(ASP.NET WebForm) const res = await axios.post('/api/upload/chunk.aspx', formData, { headers: { 'Content-Type': 'multipart/form-data' }, onUploadProgress: (e) => { if (e.lengthComputable) { // 计算实时上传速度(KB/s) const timeDiff = e.timeStamp - (task.lastTime || Date.now()); const speed = (e.loaded - task.uploadedSize) / (timeDiff || 1) / 1024; task.speed = speed.toFixed(2); task.lastTime = e.timeStamp; // 更新进度 task.uploadedSize = e.loaded; task.progress = Math.round((task.uploadedSize / task.totalSize) * 100); } } }); // 分片上传成功,更新状态 task.chunkIndex++; task.status = 'uploading'; task.statusText = `上传中(${task.chunkIndex}/${task.totalChunks})`; this.uploadNextChunk(task); // 递归上传下一个分片 } catch (err) { // 上传失败,标记状态 task.status = 'failed'; task.statusText = `上传失败:${err.response?.data?.msg || '网络错误'}`; this.isUploading = false; } }.bind(this); })(chunk, task); reader.readAsArrayBuffer(chunk); // 读取分片为ArrayBuffer(加密需要) }, } };

三、后端核心代码(ASP.NET WebForm + C#,附关键逻辑)

1. 分片上传接口(WebForm处理程序,兼容老系统)

// UploadHandler.ashx(WebForm处理程序)publicclassUploadHandler:IHttpHandler,IRequiresSessionState{publicvoidProcessRequest(HttpContextcontext){context.Response.ContentType="application/json";stringtaskId=context.Request.Form["taskId"];intchunkIndex=int.Parse(context.Request.Form["chunkIndex"]);inttotalChunks=int.Parse(context.Request.Form["totalChunks"]);stringfilePath=context.Request.Form["filePath"];HttpPostedFilechunkFile=context.Request.Files["chunk"];try{// 1. 解密分片(AES-256)byte[]encryptedData=File.ReadAllBytes(chunkFile.TempFileName);stringaesKey=GetAesKeyFromKms();// 从KMS获取动态密钥(客户需实现)byte[]decryptedData=AesDecrypt(encryptedData,aesKey);// 2. 创建存储目录(E盘路径,兼容Windows)stringstoragePath=@"E:\uploads\" + filePath; Directory.CreateDirectory(storagePath); // 3. 保存分片到服务器(非打包) string chunkPath = Path.Combine(storagePath, chunkIndex.ToString()); chunkFile.SaveAs(chunkPath); // 直接保存分片(后续合并) // 4. 记录进度到SQL Server(断点续传关键) SaveUploadProgress(taskId, filePath, chunkIndex, totalChunks, decryptedData.Length); context.Response.Write("{\"code\":200,\"msg\":\"分片上传成功\"}");}catch(Exceptionex){context.Response.Write($"{{\"code\":500,\"msg\":\"上传失败:{ex.Message}\"}}");}}}

2. 合并分片与下载接口(WebForm处理程序)

// MergeHandler.ashx(合并分片+下载)publicclassMergeHandler:IHttpHandler{publicvoidProcessRequest(HttpContextcontext){context.Response.ContentType="application/octet-stream";stringtaskId=context.Request.QueryString["taskId"];stringfilePath=context.Request.QueryString["filePath"];try{// 1. 查询分片进度(验证完整性)ListchunkIndexes=GetUploadedChunks(taskId,filePath);if(chunkIndexes.Count==0){context.Response.Write("无分片数据");return;}// 2. 合并分片(流式输出,避免内存溢出)stringstoragePath=@"E:\uploads\" + filePath; foreach (var index in chunkIndexes.OrderBy(i => i)) { string chunkPath = Path.Combine(storagePath, index.ToString()); byte[] chunkData = File.ReadAllBytes(chunkPath); context.Response.OutputStream.Write(chunkData, 0, chunkData.Length); context.Response.OutputStream.Flush(); } // 3. 清理临时分片(可选) DeleteChunks(storagePath, chunkIndexes); context.Response.End(); } catch (Exception ex) { context.Response.Write($"下载失败:{ex.Message}");}}}

四、数据库脚本(SQL Server)

-- 创建上传进度表(记录分片上传状态)CREATETABLEUploadProgress(IdINTIDENTITY(1,1)PRIMARYKEY,TaskId NVARCHAR(255)NOTNULL,-- 任务ID(如upload_1620000000_abc123)FilePath NVARCHAR(1000)NOTNULL,-- 文件存储路径(如/upload_1620000000/folder_123/file.txt)ChunkIndexINTNOTNULL,-- 当前分片索引(0开始)TotalChunksINTNOTNULL,-- 总分片数UploadedSizeBIGINTNOTNULL,-- 已上传大小(字节)StatusNVARCHAR(50)NOTNULLDEFAULT'Pending',-- 状态:Pending/Resuming/Uploading/Failed/SuccessCreateTimeDATETIMEDEFAULTGETDATE(),-- 创建时间UpdateTimeDATETIMEDEFAULTGETDATE()ONUPDATEGETDATE()-- 更新时间);-- 唯一约束(防止同一任务同一分片重复记录)CREATEUNIQUEINDEXUQ_Task_File_ChunkONUploadProgress(TaskId,FilePath,ChunkIndex);

五、部署与兼容性调试(客户最关心的)

1. IE8兼容性(客户老机器必过)

  • File API补丁:引入Blob.js(https://github.com/eligrey/Blob.js),解决File.slice不支持问题(代码中已预留位置,需在index.html中引入)。
  • FormData兼容:IE8不支持FormData,代码中已用iframe模拟上传(无需额外处理,前端自动降级)。
  • localStorage容量:IE8的localStorage容量限制为5MB,大文件进度需分块存储(代码中已用taskId分key存储)。

2. 大文件分片(20G传输关键)

  • 分片大小:选10MB是因为IE8内存限制,太大可能导致浏览器崩溃;太小会增加请求次数(实际可根据客户网络调整)。
  • 断点续传:前端用localStorage缓存已上传的分片索引和大小,后端用SQL Server记录,双重保障(客户重启电脑也能续传)。

3. 文件夹层级保留(客户核心需求)

  • 路径生成:现代浏览器用file.webkitRelativePath获取相对路径;IE8用随机生成的文件夹名兜底(需用户手动输入文件夹名,这里简化为随机字符串)。
  • 后端存储:后端按filePath字段创建目录结构(如E:\uploads\upload_1620000000\folder_123\file.txt),确保层级不变。

六、预算与合作模式(客户最关心的)

1. 预算控制(100元以内)

  • 源码一次性交付:提供完整前端Vue3组件、后端WebForm代码、数据库脚本,无后续授权费。
  • 免费技术支持:7*24小时远程协助(故障排查、版本升级、兼容性调试)。

2. 合作材料(满足客户采购要求)

  • 项目证明:提供过往外包项目合同(含项目名称、金额、验收报告)。
  • 技术资质:软件著作权证书(登记号:202XSRXXXXXX)、开发工具授权(Visual Studio 2022)。

兄弟,这套方案你拿给客户演示,保证验收时客户拍大腿说“这钱花得值”!有问题直接甩日志到群里(QQ群:374992201),老炮儿我24小时在线帮你改。记住:不会就查文档,卡壳就问群友——咱.NET程序员,接外包就是要“稳准狠”!

设置框架

安装.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/2/24 13:54:57

【企业级报销系统深度解读】:Open-AutoGLM单据提交的7个核心要点

第一章:Open-AutoGLM报销系统架构概述Open-AutoGLM 是一个基于大语言模型驱动的智能报销处理系统,旨在通过自然语言理解与自动化流程编排,实现企业费用报销的端到端自动化。该系统融合了OCR识别、语义解析、规则引擎与工作流管理模块&#xf…

作者头像 李华
网站建设 2026/2/24 10:17:19

揭秘Open-AutoGLM会话超时机制:3步实现稳定可靠的对话控制

第一章:揭秘Open-AutoGLM会话超时机制的核心原理Open-AutoGLM 作为新一代自动化大语言模型交互框架,其会话管理机制在保障系统稳定性与资源利用率方面起着关键作用。其中,会话超时机制是防止无效连接长期占用服务资源的重要设计。该机制通过动…

作者头像 李华
网站建设 2026/2/24 11:44:56

别再盲目选型了,Open-AutoGLM与NeoLoad的3个核心差异你必须知道

第一章:Open-AutoGLM与NeoLoad性能测试的核心差异概述在自动化性能测试领域,Open-AutoGLM 与 NeoLoad 代表了两种截然不同的技术路径与架构理念。前者基于开源大语言模型驱动的智能测试生成机制,后者则延续传统企业级负载测试工具的设计范式&…

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

【Open-AutoGLM多模态理解突破】:揭秘下一代AI视觉语言模型核心技术

第一章:Open-AutoGLM 多模态理解深化Open-AutoGLM 作为新一代多模态大模型,致力于打通视觉与语言之间的语义鸿沟。其核心架构融合了视觉编码器与大规模语言模型(LLM),通过跨模态对齐机制实现图像、文本乃至结构化数据的…

作者头像 李华
网站建设 2026/2/24 3:08:53

Open-AutoGLM与NeoLoad压测结果为何大相径庭(独家实测数据披露)

第一章:Open-AutoGLM与NeoLoad压测结果差异的背景与意义在现代高性能服务系统开发中,压力测试是验证系统稳定性和性能边界的关键环节。Open-AutoGLM 作为基于大语言模型驱动的自动化负载生成框架,能够智能模拟用户行为路径,动态调…

作者头像 李华
网站建设 2026/2/23 4:01:42

稀缺技术揭秘:Open-AutoGLM分布式任务断点恢复的5个关键设计原则

第一章:Open-AutoGLM分布式任务断点恢复的核心挑战在大规模语言模型训练中,Open-AutoGLM 的分布式架构面临任务中断后状态一致性与资源协调的严峻挑战。当训练任务因硬件故障、网络波动或调度策略中断时,如何准确恢复模型参数、优化器状态及数…

作者头像 李华