网站的认识,如何提高网站开发效率,wordpress ajax评论图片,外贸公司大全.NET程序员的血泪奋斗史#xff1a;从0到1搞定大文件上传#xff08;含IE8兼容#xff09;
咱福建.NET仔最近接了个外包活#xff0c;客户是做政府资料管理的#xff0c;需求就一句话#xff1a;“搞个大文件上传功能#xff0c;20G文件随便传#xff0c;文件夹要留层….NET程序员的血泪奋斗史从0到1搞定大文件上传含IE8兼容咱福建.NET仔最近接了个外包活客户是做政府资料管理的需求就一句话“搞个大文件上传功能20G文件随便传文件夹要留层级IE8也能用加密传输存储断点续传不能丢进度”客户还补刀“网上那些开源组件都是垃圾WebUploader停更了H5方案IE8跑不动我要原生JS预算100块以内源码要全文档要细不然换人”得硬着头皮上吧以下是我踩坑一周后总结的全栈解决方案含前后端代码、IE8兼容技巧、加密和断点续传实现直接复制就能用一、需求拆解客户要的到底是个啥用大白话翻译客户需求大文件上传20G文件分片传断点续传关浏览器/重启电脑不丢进度。文件夹保留层级上传/部门/2024项目/数据.xlsx下载时也得是这个结构别给我打包成zip。加密传输用SM4/AES存储也加密客户说“数据比命重要”。兼容IE8Win7IE8的老机器必须能用甲方爸爸的机器不能碰。后端ASP.NET WebForm客户不让换技术栈只能硬啃WebForm。二、前端原生JS IE8兼容的“土味”方案IE8不支持File API不能用H5的分片上传只能用Flash或iframe表单模拟异步。但客户要原生JS所以选iframe表单方案Flash已被淘汰且客户可能禁用。1. 前端核心代码Vue3兼容IE8不存在的IE8只认ES5% Page LanguageC# AutoEventWireuptrue CodeBehindUploadPage.aspx.cs InheritsBigFileUpload.UploadPage % 大文件上传IE8兼容版 // 全局变量存储上传任务、进度、加密密钥 var uploadTasks {}; // 格式{ fileId: { progress: 0, chunks: [], totalChunks: 0 } } var sm4Key 客户给的SM4密钥实际从后端动态获取; // 加密密钥硬编码仅示例实际要安全存储 // 初始化绑定文件选择按钮 window.onload function() { document.getElementById(btnSelect).onclick function() { document.getElementById(fileInput).click(); // 触发文件选择 }; document.getElementById(fileInput).onchange handleFileSelect; }; // 处理文件选择支持文件夹IE8不支持webkitdirectory只能手动输入路径 function handleFileSelect(e) { var file e.target.files[0]; if (!file) return; // 生成唯一fileId防重复 var fileId file_ Date.now(); uploadTasks[fileId] { progress: 0, chunks: [], totalChunks: Math.ceil(file.size / 2 * 1024 * 1024), // 分片大小2MB fileName: file.name, fileSize: file.size }; // 计算文件MD5用于断点校验IE8用SparkMD5的兼容版 calculateFileMD5(file, fileId); } // 计算文件MD5IE8兼容版用SparkMD5的旧版 function calculateFileMD5(file, fileId) { var chunkSize 2 * 1024 * 1024; // 2MB/片 var chunks Math.ceil(file.size / chunkSize); var spark new SparkMD5.ArrayBuffer(); var reader new FileReader(); // 分片读取文件IE8用FileReader的同步模式 function loadNextChunk(currentChunk) { var start currentChunk * chunkSize; var end Math.min(start chunkSize, file.size); reader.readAsArrayBuffer(file.slice(start, end)); // IE8可能不支持slice改用substring } reader.onload function(e) { spark.append(e.target.result); var currentChunk Math.floor(e.target.result.byteLength / (2 * 1024 * 1024)); if (currentChunk chunks - 1) { loadNextChunk(currentChunk); } else { var md5 spark.end(); uploadTasks[fileId].md5 md5; // 记录MD5断点校验用 startUpload(fileId); // 开始上传 } }; loadNextChunk(0); } // 开始上传分片断点续传 function startUpload(fileId) { var task uploadTasks[fileId]; var chunkIndex task.chunks.length; // 下一个要传的分片序号 // 检查是否已上传过该分片从localStorage读进度 var savedProgress localStorage.getItem(upload_ fileId); if (savedProgress) { task.chunks JSON.parse(savedProgress).chunks; chunkIndex task.chunks.length; } // 上传当前分片IE8用iframe模拟异步 var formData new FormData(); formData.append(fileId, fileId); formData.append(chunkIndex, chunkIndex); formData.append(totalChunks, task.totalChunks); formData.append(fileName, task.fileName); formData.append(chunk, task.file.slice(chunkIndex * 2 * 1024 * 1024, (chunkIndex 1) * 2 * 1024 * 1024)); var iframe document.createElement(iframe); iframe.style.display none; iframe.src UploadHandler.ashx?actionuploadfileId fileId chunkIndex chunkIndex; document.body.appendChild(iframe); // 监听iframe加载完成上传结果 iframe.onload function() { var response JSON.parse(iframe.contentWindow.document.body.innerText); if (response.code 200) { task.chunks.push(chunkIndex); task.progress (task.chunks.length / task.totalChunks) * 100; localStorage.setItem(upload_ fileId, JSON.stringify(task)); // 保存进度到localStorage if (task.chunks.length task.totalChunks) { mergeChunks(fileId); // 合并所有分片 } } else { alert(上传失败 response.msg); } document.body.removeChild(iframe); }; } // 合并分片调用后端接口 function mergeChunks(fileId) { var xhr new XMLHttpRequest(); xhr.open(POST, UploadHandler.ashx?actionmergefileId fileId); xhr.onload function() { var response JSON.parse(xhr.responseText); if (response.code 200) { alert(上传完成文件路径 response.filePath); localStorage.removeItem(upload_ fileId); // 清除进度 } else { alert(合并失败 response.msg); } }; xhr.send(); } 选择文件支持20G2. 前端关键技巧IE8兼容分片上传用File.slice()IE8不支持改用file.substring()实际测试IE8的File对象不完整可能需要用ActiveXObject读取文件流这里简化处理。进度保存用localStorage存上传进度IE8支持但容量有限建议分块存储比如每5%存一次。加密预处理前端用SM4加密分片示例未写需引入sm-crypto库的ES5兼容版。三、后端ASP.NET WebFormC#实现分片合并加密存储后端需要处理分片接收、断点校验、合并文件、加密存储还要兼容SQL Server。1. 后端核心代码UploadHandler.ashx// UploadHandler.ashx处理上传请求publicclassUploadHandler:IHttpHandler,IRequiresSessionState{privatestring_uploadDirHttpContext.Current.Server.MapPath(~/Uploads/Temp/);// 临时分片存储路径privatestring_encryptKey客户给的SM4密钥从配置或数据库读取;// 加密密钥publicvoidProcessRequest(HttpContextcontext){context.Response.ContentTypeapplication/json;stringactioncontext.Request[action];switch(action){caseupload:// 接收分片UploadChunk(context);break;casemerge:// 合并分片MergeChunks(context);break;default:context.Response.Write(JsonConvert.SerializeObject(new{code400,msg无效操作}));break;}}// 接收分片并存储带SM4加密privatevoidUploadChunk(HttpContextcontext){stringfileIdcontext.Request[fileId];intchunkIndexint.Parse(context.Request[chunkIndex]);inttotalChunksint.Parse(context.Request[totalChunks]);stringfileNamecontext.Request[fileName];// 校验分片是否已上传防重复if(IsChunkUploaded(fileId,chunkIndex)){context.Response.Write(JsonConvert.SerializeObject(new{code200,msg分片已上传}));return;}// 读取分片内容加密传输HttpPostedFilechunkFilecontext.Request.Files[chunk];byte[]encryptedChunknewbyte[chunkFile.ContentLength];chunkFile.InputStream.Read(encryptedChunk,0,chunkFile.ContentLength);// SM4解密分片与前端加密对应byte[]decryptedChunkSM4Decrypt(encryptedChunk,_encryptKey);// 保存分片到临时目录stringtempDirPath.Combine(_uploadDir,fileId);if(!Directory.Exists(tempDir))Directory.CreateDirectory(tempDir);stringchunkPathPath.Combine(tempDir,$chunk_{chunkIndex});File.WriteAllBytes(chunkPath,decryptedChunk);// 记录分片元数据到数据库SQL ServerSaveChunkMetadata(fileId,chunkIndex,totalChunks,fileName);context.Response.Write(JsonConvert.SerializeObject(new{code200,msg分片上传成功}));}// 合并分片并存储到目标路径privatevoidMergeChunks(HttpContextcontext){stringfileIdcontext.Request[fileId];stringtempDirPath.Combine(_uploadDir,fileId);stringfileNameGetFileNameFromMetadata(fileId);// 从数据库获取文件名stringtargetPathPath.Combine(HttpContext.Current.Server.MapPath(~/Uploads/),fileName);// 合并所有分片流式写入避免内存溢出using(FileStreamfsnewFileStream(targetPath,FileMode.Create)){for(inti0;iGetTotalChunksFromMetadata(fileId);i){stringchunkPathPath.Combine(tempDir,$chunk_{i});byte[]decryptedChunkSM4Decrypt(File.ReadAllBytes(chunkPath),_encryptKey);fs.Write(decryptedChunk,0,decryptedChunk.Length);File.Delete(chunkPath);// 删除临时分片}}// 清理临时目录Directory.Delete(tempDir);// 保存文件元数据到数据库SQL ServerSaveFileMetadata(fileId,fileName,targetPath);context.Response.Write(JsonConvert.SerializeObject(new{code200,msg合并成功,filePathtargetPath}));}// SM4加密工具方法示例需引入SM4库privatebyte[]SM4Encrypt(byte[]data,stringkey){// 实际使用BouncyCastle或专用SM4库实现returndata;// 简化示例}privatebyte[]SM4Decrypt(byte[]data,stringkey){// 实际使用BouncyCastle或专用SM4库实现returndata;// 简化示例}// 数据库操作示例使用SqlClientprivatevoidSaveChunkMetadata(stringfileId,intchunkIndex,inttotalChunks,stringfileName){using(SqlConnectionconnnewSqlConnection(Server.;DatabaseFileDB;User Idsa;Password123456;)){conn.Open();stringsqlINSERT INTO FileChunks (FileId, ChunkIndex, TotalChunks, FileName) VALUES (FileId, ChunkIndex, TotalChunks, FileName);SqlCommandcmdnewSqlCommand(sql,conn);cmd.Parameters.AddWithValue(FileId,fileId);cmd.Parameters.AddWithValue(ChunkIndex,chunkIndex);cmd.Parameters.AddWithValue(TotalChunks,totalChunks);cmd.Parameters.AddWithValue(FileName,fileName);cmd.ExecuteNonQuery();}}}2. 后端关键逻辑分片校验通过数据库记录已上传的分片避免重复上传。加密存储分片传输时用SM4加密后端解密后存储密钥需安全管理建议从配置中心获取。文件夹结构保留前端上传时传递文件夹路径如/部门/2024项目/后端根据路径创建目录示例未写需在前端fileName中包含路径后端解析后Directory.CreateDirectory。四、部署与调试IE8必看环境准备服务器装IIS启用ASP.NET WebForm支持.NET Framework 4.8。SQL Server创建数据库FileDB执行以下脚本建表CREATETABLEFileChunks(IdINTPRIMARYKEYIDENTITY,FileId NVARCHAR(50)NOTNULL,ChunkIndexINTNOTNULL,TotalChunksINTNOTNULL,FileName NVARCHAR(255)NOTNULL,UNIQUE(FileId,ChunkIndex));CREATETABLEFileMetadata(FileId NVARCHAR(50)PRIMARYKEY,FileName NVARCHAR(255)NOTNULL,FilePath NVARCHAR(500)NOTNULL,UploadTimeDATETIMEDEFAULTGETDATE());IE8兼容调试用虚拟机装Win7IE8测试上传功能重点测试分片续传、文件夹路径。前端fileInput的webkitdirectory属性在IE8无效需手动输入文件夹路径如/部门/2024项目/后端解析后创建目录。五、源代码与支持以上代码是简化版实际需要引入SM4加密库如BouncyCastle的C#版本。处理IE8的File对象兼容问题可能需要用ActiveXObject读取文件流。优化分片上传的并发控制IE8不支持Promise用setTimeout模拟异步。需要完整源码含加密、文件夹路径处理、SQL Server脚本可以加群374992201我免费发你群里还有红包和接单资源。PS客户说“能跑起来就行”但我争取做到“稳如老狗”——毕竟这是吃饭的本事冲就完事了设置框架安装.NET Framework 4.7.2https://dotnet.microsoft.com/en-us/download/dotnet-framework/net472框架选择4.7.2添加3rd引用编译项目NOSQLNOSQL无需任何配置可直接访问页面进行测试SQL使用IIS大文件上传测试推荐使用IIS以获取更高性能。使用IIS Express小文件上传测试可以使用IIS Express创建数据库配置数据库连接信息检查数据库配置访问页面进行测试相关参考文件保存位置效果预览文件上传文件刷新续传支持离线保存文件进度在关闭浏览器刷新浏览器后进行不丢失仍然能够继续上传文件夹上传支持上传文件夹并保留层级结构同样支持进度信息离线保存刷新页面关闭页面重启系统不丢失上传进度。下载完整示例下载完整示例