【一个通讯仔的悲壮求救:毕业设计要跪,求大佬救驾!】

各位江湖好汉,俺是山西某高校通讯专业的大三狗,眼瞅着毕业答辩在即,却被“文件管理系统”这个妖孽项目折磨得欲仙欲死。导师要求支持10G大文件上传、断点续传、加密存储,还要兼容IE8和国产信创浏览器(龙芯、红莲花、奇安信),这分明是要我化身“浏览器兼容性灭霸”啊!


💻 前端血泪史(Vue3 + 原生JS魔改版)

// webuploader-wrapper.js(兼容IE8+国产浏览器的魔改版)  
class SuperUploader {  
  constructor(options) {  
    this.chunks = []; // 存储分片信息  
    this.fileMd5 = ''; // 文件唯一标识  
    this.isOldIE = navigator.userAgent.indexOf('MSIE') > -1 || navigator.userAgent.indexOf('Trident') > -1;  
    this.isXinChuang = /Lotus|RedLotus|QAX|360SE/.test(navigator.userAgent); // 检测国产浏览器  

    // 兼容IE8的XMLHttpRequest封装  
    this.getXHR = () => {  
      if (this.isOldIE) {  
        try { return new ActiveXObject("Msxml2.XMLHTTP"); } catch (e) { return new ActiveXObject("Microsoft.XMLHTTP"); }  
      }  
      return new XMLHttpRequest();  
    };  

    // 计算文件MD5(IE8直接用文件名+大小当伪MD5)  
    this.calculateMD5 = (file, callback) => {  
      if (this.isOldIE) {  
        callback(`${file.name}-${file.size}-${file.lastModified}`);  
      } else {  
        // 正常MD5计算(此处省略200行代码)  
      }  
    };  
  }  

  // 文件夹上传(递归遍历+FormData魔改,兼容国产浏览器)  
  uploadFolder(folder, parentPath = '') {  
    const files = [];  
    const dirReader = folder.createReader();  

    dirReader.readEntries(entries => {  
      entries.forEach(entry => {  
        if (entry.isFile) {  
          entry.file(file => {  
            files.push({  
              path: `${parentPath}/${entry.name}`,  
              file  
            });  
          });  
        } else {  
          this.uploadFolder(entry, `${parentPath}/${entry.name}`);  
        }  
      });  

      // 兼容国产浏览器的异步处理  
      if (this.isXinChuang) {  
        setTimeout(() => this.processFiles(files), 100);  
      } else {  
        Promise.all(files).then(() => this.processFiles(files));  
      }  
    });  
  }  
}  

🖥️ 后端生死状(ASP.NET WebForm版)

// UploadHandler.aspx.cs(要命版)  
public partial class UploadHandler : System.Web.UI.Page {  
    protected void Page_Load(object sender, EventArgs e) {  
        if (Request.Form["action"] == "check_chunk") {  
            CheckChunk();  
        } else if (Request.Form["action"] == "merge") {  
            MergeChunks();  
        }  
    }  

    // 检查分片是否存在(兼容IE8的表单解析)  
    private void CheckChunk() {  
        string fileMd5 = Request.Form["fileMd5"];  
        int chunkIndex = int.Parse(Request.Form["chunkIndex"]);  
        string chunkPath = Server.MapPath($"~/Uploads/{fileMd5}/{chunkIndex}");  

        Response.Write(File.Exists(chunkPath) ? "1" : "0");  
        Response.End();  
    }  

    // 合并分片(SQL Server记录元数据)  
    private void MergeChunks() {  
        string fileMd5 = Request.Form["fileMd5"];  
        int totalChunks = int.Parse(Request.Form["totalChunks"]);  
        string fileName = Request.Form["fileName"];  

        // 检查是否所有分片已上传  
        string tempDir = Server.MapPath($"~/Uploads/{fileMd5}/");  
        if (Directory.GetFiles(tempDir).Length == totalChunks) {  
            // 合并文件(此处省略50行文件操作代码)  
            string savePath = Server.MapPath($"~/Files/{fileName}");  
            using (var fs = new FileStream(savePath, FileMode.Create)) {  
                for (int i = 0; i < totalChunks; i++) {  
                    byte[] bytes = File.ReadAllBytes($"{tempDir}{i}");  
                    fs.Write(bytes, 0, bytes.Length);  
                }  
            }  

            // 记录数据库(SQL Server)  
            using (SqlConnection conn = new SqlConnection("Server=.;Database=FileManager;User=sa;Password=123456;")) {  
                conn.Open();  
                SqlCommand cmd = new SqlCommand(  
                    "INSERT INTO Files (Name, Path, Size, UploadTime) VALUES (@Name, @Path, @Size, GETDATE())", conn);  
                cmd.Parameters.AddWithValue("@Name", fileName);  
                cmd.Parameters.AddWithValue("@Path", savePath);  
                cmd.Parameters.AddWithValue("@Size", new FileInfo(savePath).Length);  
                cmd.ExecuteNonQuery();  
            }  

            Response.Write("{\"status\":\"success\"}");  
        } else {  
            Response.Write("{\"status\":\"pending\"}");  
        }  
        Response.End();  
    }  
}  

🎯 血泪经验总结

  1. 浏览器兼容大法

    • IE8用ActiveXObject替代XMLHttpRequest
    • 国产浏览器(如红莲花)需降级处理异步逻辑
    • 文件路径统一用/避免转义问题
  2. 断点续传秘籍

    // 本地存储进度(兼容IE8的降级方案)  
    const saveProgress = (fileMd5, progress) => {  
      if (window.localStorage) {  
        localStorage.setItem(`upload_${fileMd5}`, JSON.stringify(progress));  
      } else if (document.documentElement.addBehavior) {  
        // IE8及以下用userData存储  
        const storage = document.createElement('div');  
        storage.addBehavior('#default#userData');  
        storage.setAttribute('progress', JSON.stringify(progress));  
        storage.save(`upload_${fileMd5}`);  
      }  
    };  
    
  3. 加密传输方案

    • 前端用CryptoJS加密(需引入polyfill支持IE8)
    • 后端用System.Security.Cryptography解密
    • 传输走HTTPS(IIS免费证书)

🙏 江湖救急

现诚征各路大侠:

  1. 加入QQ群:374992201(进群领1-99元红包,推荐项目拿50%提成!)
  2. 求师哥师姐内推工作(通讯/信息安全方向,可接受996福报)
  3. 需要完整项目代码的兄弟,群里每天晚上8点准时发车!

(附:导师说项目要是能过,请群主吃刀削面管够!🍜)


PS:群里还有“国产浏览器兼容性测试套餐”,包括龙芯、红莲花、奇安信的虚拟机环境,欢迎来白嫖!🚀

设置框架

安装.NET Framework 4.7.2
https://dotnet.microsoft.com/en-us/download/dotnet-framework/net472
框架选择4.7.2
Alt

添加3rd引用

Alt

编译项目

Alt

NOSQL

NOSQL无需任何配置可直接访问页面进行测试
Alt

SQL

使用IIS
大文件上传测试推荐使用IIS以获取更高性能。
Alt

使用IIS Express

小文件上传测试可以使用IIS Express
Alt

创建数据库

Alt

配置数据库连接信息

Alt

检查数据库配置

Alt

访问页面进行测试

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

效果预览

文件上传

文件上传

文件刷新续传

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

文件夹上传

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

下载完整示例

下载完整示例

Logo

为武汉地区的开发者提供学习、交流和合作的平台。社区聚集了众多技术爱好者和专业人士,涵盖了多个领域,包括人工智能、大数据、云计算、区块链等。社区定期举办技术分享、培训和活动,为开发者提供更多的学习和交流机会。

更多推荐