河南郑州程序员的大文件传输系统开发实战:基于WebUploader的国产化全栈解决方案
一、项目背景与需求分析
1.1 核心需求
- 大文件传输:支持20GB+文件上传/下载,需分片传输、断点续传。
- 文件夹结构保留:上传文件夹时需完整保留层级关系(前端递归解析 + 后端重组)。
- 全浏览器兼容:
- 传统浏览器:IE8+、Chrome、Firefox、Edge
- 信创浏览器:龙芯浏览器、红莲花浏览器、奇安信安全浏览器
- 加密传输:
- 国密算法:SM4(需引入第三方库如
gmssl.js) - 国际标准:AES-256(浏览器原生
Crypto API或crypto-js)
- 国密算法:SM4(需引入第三方库如
- 国产化环境适配:
- 操作系统:统信UOS、中标麒麟、银河麒麟
- 数据库:达梦、人大金仓(兼容SQL Server语法)
- 云存储:阿里云OSS、华为云OBS、腾讯云COS、百度云BOS
- 后端技术栈:.NET Core 3.1/5.0(跨平台兼容Linux/Windows)
- 前端技术栈:Vue2 + WebUploader(需二次开发支持文件夹上传)
1.2 痛点与挑战
- WebUploader原生缺陷:
- 仅支持单文件上传,文件夹上传需手动扩展(通过``)
- 分片逻辑需自行实现(参考
File.slice())
- IE8兼容性:
- 需引入
es5-shim和json2.jspolyfill - 替换
Promise为jQuery.Deferred
- 需引入
- 国产化数据库适配:
- 达梦/人大金仓的SQL方言差异(如分页语法
LIMITvsROW_NUMBER())
- 达梦/人大金仓的SQL方言差异(如分页语法
- 加密性能优化:
- 大文件加密需流式处理(避免内存溢出)
二、技术方案设计与实现
2.1 前端实现(Vue2 + WebUploader扩展)
2.1.1 文件夹上传核心代码
// src/components/FileUploader.vue
import WebUploader from 'webuploader';
import CryptoJS from 'crypto-js'; // 或引入SM4库
export default {
data() {
return {
fileList: [],
uploader: null,
chunkSize: 5 * 1024 * 1024, // 5MB分片
};
},
methods: {
handleFolderSelect(e) {
const files = e.target.files;
const fileTree = this.parseFolder(files); // 递归解析文件夹结构
this.fileList = fileTree;
this.initUploader(fileTree);
},
parseFolder(files) {
const tree = [];
for (let i = 0; i < files.length; i++) {
const file = files[i];
const pathParts = file.webkitRelativePath.split('/');
const fileName = pathParts.pop();
const dirPath = pathParts.join('/') || '/';
tree.push({
id: file.lastModified + '-' + file.name,
path: file.webkitRelativePath,
name: fileName,
size: file.size,
type: file.type,
dir: dirPath,
});
}
return tree;
},
initUploader(fileList) {
this.uploader = WebUploader.create({
swf: '/static/Uploader.swf', // IE8兼容
server: '/api/upload',
chunked: true,
chunkSize: this.chunkSize,
threads: 3,
formData: {
encryptType: 'AES', // 或 'SM4'
},
});
fileList.forEach((file) => {
const reader = new FileReader();
reader.onload = (e) => {
// 加密文件内容(示例:AES)
const encrypted = CryptoJS.AES.encrypt(
e.target.result,
'your-secret-key'
).toString();
// 模拟分片上传(实际需调用uploader.upload方法)
this.uploadChunk(file, encrypted, 0);
};
reader.readAsArrayBuffer(file); // 或使用slice分片读取
});
},
uploadChunk(file, encryptedData, chunkIndex) {
// 实际需通过WebUploader的API实现分片上传
console.log(`Uploading chunk ${chunkIndex} of ${file.path}`);
},
},
};
2.1.2 IE8兼容性处理
- 引入Polyfill:
- 替换
fetch为jQuery.ajax或axios(需配置xhr兼容模式)。
2.2 后端实现(.NET Core)
2.2.1 文件分片接收与重组
// Controllers/UploadController.cs
[ApiController]
[Route("api/[controller]")]
public class UploadController : ControllerBase
{
private readonly IWebHostEnvironment _env;
private readonly IDatabaseService _db; // 抽象数据库操作
public UploadController(IWebHostEnvironment env, IDatabaseService db)
{
_env = env;
_db = db;
}
[HttpPost]
public async Task Upload()
{
var form = await Request.ReadFormAsync();
var file = form.Files[0];
var chunkIndex = int.Parse(form["chunkIndex"]);
var totalChunks = int.Parse(form["totalChunks"]);
var fileId = form["fileId"];
var encryptType = form["encryptType"]; // "AES"或"SM4"
// 临时存储分片
var tempPath = Path.Combine(_env.WebRootPath, "temp", fileId.ToString());
Directory.CreateDirectory(tempPath);
var chunkPath = Path.Combine(tempPath, $"{chunkIndex}.dat");
using (var stream = new FileStream(chunkPath, FileMode.Create))
{
await file.CopyToAsync(stream);
}
// 如果是最后一个分片,则合并文件
if (chunkIndex == totalChunks - 1)
{
var finalPath = Path.Combine(_env.WebRootPath, "uploads", file.FileName);
MergeChunks(tempPath, finalPath, totalChunks);
// 解密文件(根据encryptType调用不同算法)
if (encryptType == "AES")
{
DecryptFileAES(finalPath, "your-secret-key");
}
else if (encryptType == "SM4")
{
// 调用SM4解密库
}
// 记录文件元数据到数据库
await _db.SaveFileRecord(new FileRecord
{
Name = file.FileName,
Path = finalPath,
Size = file.Length,
UploadTime = DateTime.Now,
});
Directory.Delete(tempPath, true);
return Ok(new { success = true, path = finalPath });
}
return Ok(new { success = true, message = "Chunk uploaded" });
}
private void MergeChunks(string tempDir, string outputPath, int totalChunks)
{
using (var outputStream = new FileStream(outputPath, FileMode.Create))
{
for (int i = 0; i < totalChunks; i++)
{
var chunkPath = Path.Combine(tempDir, $"{i}.dat");
var chunkData = System.IO.File.ReadAllBytes(chunkPath);
outputStream.Write(chunkData, 0, chunkData.Length);
System.IO.File.Delete(chunkPath);
}
}
}
private void DecryptFileAES(string inputPath, string key)
{
// 实现AES解密逻辑(需处理大文件流式解密)
}
}
2.2.2 国产化数据库适配
- 通过
IDatabaseService抽象层隔离数据库差异:public interface IDatabaseService { Task SaveFileRecord(FileRecord record); Task> GetFilesByUser(string userId); } // 达梦数据库实现 public class DamengDatabaseService : IDatabaseService { private readonly string _connString; public DamengDatabaseService(IConfiguration config) { _connString = config["ConnectionStrings:Dameng"]; } public async Task SaveFileRecord(FileRecord record) { using (var conn = new DmConnection(_connString)) { await conn.OpenAsync(); var cmd = new DmCommand( "INSERT INTO FILES(NAME, PATH, SIZE, UPLOAD_TIME) VALUES(@name, @path, @size, @time)", conn ); cmd.Parameters.AddWithValue("@name", record.Name); cmd.Parameters.AddWithValue("@path", record.Path); cmd.Parameters.AddWithValue("@size", record.Size); cmd.Parameters.AddWithValue("@time", record.UploadTime); await cmd.ExecuteNonQueryAsync(); } } }
三、部署与测试
3.1 国产化环境部署
- 统信UOS:
# 安装.NET Core运行时 sudo apt-get install dotnet-sdk-5.0 # 运行项目 dotnet run --project YourProject.csproj - 银河麒麟:
- 需手动安装
libgdiplus(用于图像处理)。
- 需手动安装
3.2 信创浏览器测试
- 龙芯浏览器:
- 检查
webkitdirectory支持情况(可能需降级为Flash上传组件)。
- 检查
- 奇安信安全浏览器:
- 启用“兼容模式”以支持IE8级API。
四、寻求社区支持
4.1 现有问题
- WebUploader文件夹上传在IE8下失效:需替换为Flash上传组件(如
Plupload)。 - SM4加密性能瓶颈:大文件解密耗时过长。
- 达梦数据库分页查询语法:与SQL Server差异较大。
4.2 加入技术交流群
- QQ群:374992201(备注“大文件传输开发”)
- 需求:
- 免费获取完整源码(前端+后端+数据库脚本)
- 7×24小时技术支持(优先解决国产化环境问题)
- 联合优化加密与分片传输性能
(完)
P.S.:本项目已实现核心功能,但需进一步测试信创环境兼容性。欢迎大神贡献代码或提供优化建议!
设置框架
安装.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

创建数据库

配置数据库连接信息

检查数据库配置

访问页面进行测试

相关参考:
文件保存位置,
效果预览
文件上传

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

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

829

被折叠的 条评论
为什么被折叠?



