news 2026/10/30 6:08:36

国密加密在JQuery大文件上传中的实现思路与代码?

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
国密加密在JQuery大文件上传中的实现思路与代码?

大文件上传解决方案

作为一个同样接外包接到手软的.NET老油条,我完全理解你既要兼容IE8又要20G文件上传还要100块预算的"无理要求"。来,给你整一套"饿不死套餐"!

前端实现 - 兼容IE8的土味方案

穷逼版大文件上传 /* 祖传CSS,兼容IE8 */ .upload-area { border: 2px dashed #ccc; padding: 20px; text-align: center; margin: 20px; } .progress-container { width: 100%; background-color: #f5f5f5; margin: 10px 0; } .progress-bar { height: 20px; background-color: #4CAF50; width: 0%; } .file-list { margin: 20px; border: 1px solid #ddd; padding: 10px; } 大文件上传(兼容IE8版) 拖放文件或文件夹到此处 或 选择文件/文件夹 等待上传文件... 开始上传 暂停 继续 加密方式: SM4国密 AES // 兼容IE8的JSON if (typeof JSON === "undefined") { document.write('<scriptsrc="https://cdnjs.cloudflare.com/ajax/libs/json2/20150503/json2.min.js"><\/script>'); } // 上传队列 var uploadQueue = []; var currentUpload = null; var chunkSize = 5 * 1024 * 1024; // 5MB分块 // 文件选择处理 document.getElementById('fileInput').addEventListener('change', function(e) { handleFiles(e.target.files); }); // 拖放处理 var dropArea = document.getElementById('dropArea'); dropArea.addEventListener('dragover', function(e) { e.preventDefault(); dropArea.style.borderColor = '#4CAF50'; }); dropArea.addEventListener('dragleave', function() { dropArea.style.borderColor = '#ccc'; }); dropArea.addEventListener('drop', function(e) { e.preventDefault(); dropArea.style.borderColor = '#ccc'; handleFiles(e.dataTransfer.files); }); // 处理文件选择 function handleFiles(files) { var fileList = document.getElementById('fileList'); fileList.innerHTML = ''; for (var i = 0; i < files.length; i++) { var file = files[i]; var fileItem = document.createElement('div'); fileItem.innerHTML = file.name + ' (' + formatFileSize(file.size) + ')'; fileList.appendChild(fileItem); uploadQueue.push({ file: file, progress: 0, status: 'pending' }); } } // 开始上传 function startUpload() { if (uploadQueue.length === 0) return; currentUpload = uploadQueue[0]; uploadFile(currentUpload); } // 上传文件 function uploadFile(fileItem) { var file = fileItem.file; var fileId = generateFileId(file); var totalChunks = Math.ceil(file.size / chunkSize); // 从本地存储加载断点 var resumeChunk = localStorage.getItem('resume_' + fileId) || 0; // 上传分块 for (var chunkIndex = resumeChunk; chunkIndex < totalChunks; chunkIndex++) { if (fileItem.status === 'paused') break; var start = chunkIndex * chunkSize; var end = Math.min(start + chunkSize, file.size); var chunk = file.slice(start, end); // 加密分块(伪代码) var encryptedChunk = encryptChunk( chunk, document.getElementById('encryptionType').value, document.getElementById('encryptionKey').value ); var formData = new FormData(); formData.append('fileId', fileId); formData.append('chunkIndex', chunkIndex); formData.append('totalChunks', totalChunks); formData.append('fileName', file.name); formData.append('filePath', file.webkitRelativePath || ''); formData.append('fileSize', file.size); formData.append('chunkData', encryptedChunk); formData.append('encryption', document.getElementById('encryptionType').value); // AJAX上传(兼容IE8) var xhr = new XMLHttpRequest(); xhr.open('POST', '/api/upload/chunk', false); // 同步上传,IE8不支持Promise xhr.upload.onprogress = function(e) { var loaded = chunkIndex * chunkSize + e.loaded; fileItem.progress = Math.round((loaded / file.size) * 100); updateProgress(); }; xhr.onreadystatechange = function() { if (xhr.readyState === 4) { if (xhr.status === 200) { // 保存断点 localStorage.setItem('resume_' + fileId, chunkIndex + 1); if (chunkIndex === totalChunks - 1) { // 合并文件 mergeFile(fileId); fileItem.status = 'completed'; uploadQueue.shift(); startUpload(); } } else { console.error('上传失败:', xhr.responseText); } } }; xhr.send(formData); } } // 暂停上传 function pauseUpload() { if (currentUpload) { currentUpload.status = 'paused'; } } // 继续上传 function resumeUpload() { if (currentUpload && currentUpload.status === 'paused') { currentUpload.status = 'uploading'; uploadFile(currentUpload); } } // 合并文件 function mergeFile(fileId) { var xhr = new XMLHttpRequest(); xhr.open('POST', '/api/upload/merge', false); xhr.setRequestHeader('Content-Type', 'application/json'); xhr.onreadystatechange = function() { if (xhr.readyState === 4 && xhr.status === 200) { console.log('文件合并成功:', xhr.responseText); localStorage.removeItem('resume_' + fileId); } }; xhr.send(JSON.stringify({ fileId: fileId, encryption: document.getElementById('encryptionType').value })); } // 生成文件ID function generateFileId(file) { return file.name + '_' + file.size + '_' + file.lastModifiedDate.getTime(); } // 加密分块(伪实现) function encryptChunk(chunk, algorithm, key) { // 实际项目中应该使用Web Crypto API或相应库 console.log('使用' + algorithm + '加密分块,密钥:', key); return chunk; } // 更新进度显示 function updateProgress() { var progressBars = document.querySelectorAll('.progress-bar'); for (var i = 0; i < progressBars.length; i++) { progressBars[i].style.width = uploadQueue[i].progress + '%'; } } // 格式化文件大小 function formatFileSize(bytes) { if (bytes === 0) return '0 B'; var k = 1024; var sizes = ['B', 'KB', 'MB', 'GB', 'TB']; var i = Math.floor(Math.log(bytes) / Math.log(k)); return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i]; }

后端实现 - ASP.NET WebForm版

FileUploadHandler.ashx

<%@WebHandlerLanguage="C#"Class="FileUploadHandler"%>usingSystem;usingSystem.Web;usingSystem.IO;usingSystem.Collections.Generic;usingSystem.Linq;publicclassFileUploadHandler:IHttpHandler{publicvoidProcessRequest(HttpContextcontext){context.Response.ContentType="application/json";try{stringaction=context.Request["action"];switch(action){case"upload_chunk":HandleChunkUpload(context);break;case"merge_file":HandleMergeFile(context);break;default:context.Response.Write("{\"error\":\"无效操作\"}");break;}}catch(Exceptionex){context.Response.Write("{\"error\":\""+ex.Message+"\"}");}}privatevoidHandleChunkUpload(HttpContextcontext){stringfileId=context.Request["fileId"];intchunkIndex=int.Parse(context.Request["chunkIndex"]);inttotalChunks=int.Parse(context.Request["totalChunks"]);stringfileName=context.Request["fileName"];stringfilePath=context.Request["filePath"];longfileSize=long.Parse(context.Request["fileSize"]);stringencryption=context.Request["encryption"];HttpPostedFilechunkData=context.Request.Files["chunkData"];// 保存分块stringchunkDir=GetChunkDir(fileId);if(!Directory.Exists(chunkDir)){Directory.CreateDirectory(chunkDir);}stringchunkPath=Path.Combine(chunkDir,chunkIndex.ToString()+".chunk");chunkData.SaveAs(chunkPath);// 保存断点信息SaveResumeInfo(fileId,chunkIndex+1,totalChunks);context.Response.Write("{\"success\":true}");}privatevoidHandleMergeFile(HttpContextcontext){stringfileId=context.Request["fileId"];stringencryption=context.Request["encryption"];// 获取分块信息varresumeInfo=GetResumeInfo(fileId);if(resumeInfo==null){thrownewException("找不到文件断点信息");}stringchunkDir=GetChunkDir(fileId);stringfileName=Path.GetFileNameWithoutExtension(resumeInfo.FileName);stringfileExt=Path.GetExtension(resumeInfo.FileName);// 创建目标文件stringsaveDir=Path.Combine(AppDomain.CurrentDomain.BaseDirectory,"Uploads");if(!string.IsNullOrEmpty(resumeInfo.FilePath)){saveDir=Path.Combine(saveDir,resumeInfo.FilePath);}if(!Directory.Exists(saveDir)){Directory.CreateDirectory(saveDir);}stringsavePath=Path.Combine(saveDir,fileName+fileExt);using(FileStreamfs=newFileStream(savePath,FileMode.Create)){// 合并所有分块for(inti=0;i<resumeInfo.TotalChunks;i++){stringchunkPath=Path.Combine(chunkDir,i+".chunk");byte[]chunkData=File.ReadAllBytes(chunkPath);// 解密数据(伪实现)byte[]decryptedData=DecryptChunk(chunkData,encryption);fs.Write(decryptedData,0,decryptedData.Length);// 删除临时分块File.Delete(chunkPath);}}// 删除分块目录Directory.Delete(chunkDir);// 清理断点信息ClearResumeInfo(fileId);context.Response.Write("{\"success\":true, \"filePath\":\""+savePath.Replace("\\","/")+"\"}");}privatestringGetChunkDir(stringfileId){returnPath.Combine(AppDomain.CurrentDomain.BaseDirectory,"Temp",fileId);}privatevoidSaveResumeInfo(stringfileId,intchunkIndex,inttotalChunks){varinfo=newResumeInfo{FileId=fileId,ChunkIndex=chunkIndex,TotalChunks=totalChunks,LastUpdate=DateTime.Now};stringinfoPath=Path.Combine(GetChunkDir(fileId),"resume.info");File.WriteAllText(infoPath,Newtonsoft.Json.JsonConvert.SerializeObject(info));}privateResumeInfoGetResumeInfo(stringfileId){stringinfoPath=Path.Combine(GetChunkDir(fileId),"resume.info");if(File.Exists(infoPath)){returnNewtonsoft.Json.JsonConvert.DeserializeObject(File.ReadAllText(infoPath));}returnnull;}privatevoidClearResumeInfo(stringfileId){stringinfoPath=Path.Combine(GetChunkDir(fileId),"resume.info");if(File.Exists(infoPath)){File.Delete(infoPath);}}privatebyte[]DecryptChunk(byte[]encryptedData,stringalgorithm){// 实际项目中应该使用SM4/AES解密returnencryptedData;}publicboolIsReusable{get{returntrue;}}privateclassResumeInfo{publicstringFileId{get;set;}publicstringFileName{get;set;}publicstringFilePath{get;set;}publicintChunkIndex{get;set;}publicintTotalChunks{get;set;}publicDateTimeLastUpdate{get;set;}}}

数据库设计 - 乞丐版

CREATETABLE[dbo].[FileUploadRecords](50NOTNULL,255NOTNULL,512NULL,[FileSize][bigint]NOTNULL,512NOTNULL,20NULL,20NULL,50NULL,[UploadTime][datetime]NOTNULL,[CompleteTime][datetime]NULL,CONSTRAINT[PK_FileUploadRecords]PRIMARYKEYCLUSTERED([Id]ASC))

部署指南 - 手把手教学

  1. 前端部署:

    • 把HTML文件扔到IIS网站目录
    • 确保启用静态内容
  2. 后端部署:

    • 在Visual Studio中发布WebForm项目
    • 部署到IIS,确保应用程序池使用.NET 4.0
  3. 权限设置:

    • 给Uploads和Temp目录添加IIS_IUSRS写权限
  4. IE8兼容性:

    • 在IIS中添加MIME类型:.json application/json
    • 在页面添加X-UA-Compatible标签:

注意事项

  1. 加密部分:实际项目中应该使用正规加密库,这里只是伪实现

  2. 性能问题:IE8下同步上传会阻塞页面,用户体验极差,但甲方爸爸要兼容没办法

  3. 安全性:记得在前端和后端都做文件类型检查,防止上传恶意文件

  4. 预算问题:100块真的做不了什么,建议跟甲方商量加点钱

最后忠告

  1. 下次接单前先谈好兼容性要求
  2. IE8真的该淘汰了,尽量说服客户升级
  3. 100块的项目别指望7x24支持,除非你想饿死
  4. 加群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

创建数据库

配置数据库连接信息

检查数据库配置

访问页面进行测试


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

效果预览

文件上传

文件刷新续传

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

文件夹上传

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

下载完整示例

下载完整示例

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/29 23:27:42

四时四名,一山万象:朝鲜金刚山的锦绣风姿

金刚山属太白山脉核心段&#xff0c;横跨金刚郡、通川郡等多地及韩国麟蹄郡&#xff0c;总面积达530平方公里。这座秀丽名山东西绵延40公里&#xff0c;南北纵贯60公里&#xff0c;海拔千米以上山峰逾60座&#xff0c;主峰毗卢峰以1638米的海拔雄踞群峰之上。山名源自佛教“金刚…

作者头像 李华
网站建设 2026/10/29 23:30:08

基于Spring Boot的果蔬销售系统

基于Spring Boot的果蔬销售系统&#xff08;含推荐算法&#xff09;介绍 基于Spring Boot的果蔬销售系统是一款结合智能推荐算法的电商平台&#xff0c;旨在优化果蔬销售流程&#xff0c;提升用户体验和销售效率。系统通过整合现代Web开发技术和个性化推荐算法&#xff0c;解决…

作者头像 李华
网站建设 2026/10/29 5:02:26

Scala Collection(集合)

Scala Collection(集合) Scala 作为一种多范式编程语言,在集合处理方面提供了丰富的工具和方法。Scala 的集合操作是语言的核心特性之一,使得处理数据集变得更加高效和直观。本文将深入探讨 Scala 集合的概念、类型以及常用操作。 引言 在 Scala 中,“集合”指的是一组…

作者头像 李华
网站建设 2026/10/29 22:24:24

介观交通流仿真软件:DynusT_(11).交通事件管理

交通事件管理 在交通流仿真中&#xff0c;交通事件管理是一个重要的模块&#xff0c;用于模拟和管理各种交通事件&#xff0c;如交通事故、交通管制、道路施工等。这些事件可以显著影响交通流的特性和仿真结果。本节将详细介绍如何在仿真软件中实现交通事件管理&#xff0c;包…

作者头像 李华
网站建设 2026/10/29 7:25:05

django基于Python天气分析系统

Django基于Python的天气分析系统是一个集成了数据采集、处理、分析和可视化功能的综合性系统。以下是对该系统的详细介绍&#xff1a; 一、系统架构与技术栈 1.后端框架&#xff1a;Django作为后端框架&#xff0c;负责处理业务逻辑&#xff0c;如数据的接收、存储和初步处理&a…

作者头像 李华
网站建设 2026/10/30 3:00:43

python基于大数据的分析长沙旅游景点推荐系统

Python基于大数据的分析长沙旅游景点推荐系统是一种高效、个性化的旅游辅助工具。以下是对该系统的详细介绍&#xff1a; 一、系统背景与意义 长沙作为湖南省的省会城市&#xff0c;拥有丰富的旅游资源&#xff0c;包括自然风光、历史文化、美食等。然而&#xff0c;随着旅游业…

作者头像 李华