云计算百科
云计算领域专业知识百科平台

国防领域,asp.net如何处理文件夹上传的安全性问题?

【一个武汉40岁C#码农的2G文件上传渡劫记:从WebUploader到光谷码农自救指南】


"张总,这个需求…可能要加钱。"我抿了口热干面汤,盯着电脑屏幕上"支持2G文件批量上传"的需求文档,额头上的汗珠顺着汉味十足的T恤领口往下淌。作为光谷软件园里"既能修打印机又能写WebAPI"的全能型选手,我深知这次要面对的是三重暴击:Vue2的兼容性、SQL Server的存储压力,还有那个该死的WebUploader——它现在就像个被热干面汤泡软的筷子,在控制台里软趴趴地躺着。

第一幕:WebUploader的"热干面式崩溃"

"看!它动了!"我兴奋地指着屏幕上突然跳到99%的进度条,下一秒Chrome标签页就白屏了。这个百度开源的组件就像个行为艺术家:

  • 分片上传?能工作,但偶尔会把第13片传到汉口火车站(后来发现是Nginx的client_max_body_size设置成了2M)
  • 跨浏览器兼容?在360安全浏览器里会表演"进度条卡顿魔术",在QQ浏览器里直接显示"NaN%"
  • 断点续传?客户重启路由器后,所有分片都会集体玩"消失的江汉路"

最绝的是错误处理:

// 前端发来的神秘代码(武昌口音版)
uploader.on('error', function(type) {
if(type === 'F_DUPLICATE') {
alert('文件已存在,但后端可能没收到这个消息,就像你喊服务员加杯豆浆他没听到');
} else {
console.log('出错了,但我不知道怎么描述,就像你问路时对方说"往那头走"');
}
});

第二幕:.NET Core与Vue2的"长江大桥式沟通"

"前端说需要获取上传速度!"我冲着电话大喊,嘴里还嚼着周黑鸭鸭脖。后端小哥(其实也是我)的声线透着绝望:“哥,WebUploader的文档比东湖的水还深…”

于是我们开启了量子纠缠式开发:

// 后端API(喝到第五杯碧螺春后的产物)
[HttpPost("upload-chunk")]
public async Task UploadChunk(IFormFile file, string fileHash, int chunkIndex)
{
try {
var chunkPath = Path.Combine("uploads", fileHash, $"{chunkIndex}.part");
await using var stream = new FileStream(chunkPath, FileMode.Create);
await file.CopyToAsync(stream); // 偶尔会抛出"神秘异常",就像长江突然涨水
return Ok(new { success = true }); // 其实可能没成功,就像你以为抢到了粮票结果发现是去年的
} catch {
return StatusCode(500, "服务器说它想静静,就像你老婆说'我没事'");
}
}

// 前端调用(Vue2的魔法,掺杂着汉口话注释)
uploadChunk(chunk) {
const formData = new FormData();
formData.append('file', chunk.file);
formData.append('fileHash', this.fileHash);
formData.append('chunkIndex', chunk.index);

axios.post('/api/upload-chunk', formData, {
onUploadProgress: () => {
// 这个回调会随机触发3次,就像公交司机说"马上到"
}
});
}

第三幕:SQL Server的"户部巷式拥堵"

当客户问"能不能显示所有上传任务的历史记录"时,我盯着那台只有8G内存的云服务器陷入了沉思:

— 最初的设计(天真版,就像以为光谷步行街周末不堵车)
CREATE TABLE UploadTasks (
Id UNIQUEIDENTIFIER PRIMARY KEY,
FileName NVARCHAR(255),
FileSize BIGINT, — 2G文件就是2147483648
Status INT, — 0=上传中 1=完成 2=失败 3=合并中…
CreatedAt DATETIME2,
— 省略了5个关联表的设计,就像省略了热干面的萝卜丁
);

直到测试时发现:

  • 插入1000条记录后,查询"进行中的任务"需要2.8秒(就像等643路公交)
  • 没有给FileHash列加索引(别问我怎么知道的,就像别问我为什么总错过地铁末班车)
  • 当Nginx超时断开连接时,.NET Core还在傻乎乎地插入分片记录(就像你举着手机找信号时对方已经挂断)
  • 合并文件时,FileStream直接吃掉了4G内存(就像你试图把整碗热干面一口吞下)
  • 第四幕:绝地求生方案(光谷特供版)

    经过三天三夜的谷歌搜索(和两包精武鸭脖),我制定了新方案:

    前端改造计划(汉味优化):

  • 弃用WebUploader,改用uppy.io(至少文档是2024年的,不像某些武汉公交时刻表)
  • 实现真正的断点续传:// 用IndexedDB存储已上传分片(武汉方言版注释)
    const dbPromise = idb.open('UploadDB', 1, upgradeDB => {
    upgradeDB.createObjectStore('chunks', { keyPath: 'id' }); // 就像给每片鸭脖编号
    });
  • 添加心跳检测,防止浏览器假死(就像防止公交司机突然打瞌睡)
  • 用WebSocket实时显示上传速度(虽然.NET Core的SignalR更香,但学不动啊,就像学不会武汉话的儿化音)
  • 后端自救指南(东湖特供):

  • 用MemoryMappedFile替代普通FileStream处理大文件:// 合并分片时不再吃内存(就像不再把整碗热干面汤喝光)
    using (var mmf = MemoryMappedFile.CreateFromFile("final.dat", FileMode.Create)) {
    for (int i = 0; i < totalChunks; i++) {
    var chunkPath = Path.Combine("uploads", fileHash, $"{i}.part");
    // 内存映射文件操作…(就像分批次过长江大桥)
    }
    }
  • 添加速率限制中间件:// 防止客户端疯狂上传(就像限制过早摊主不能同时煮20碗热干面)
    app.Use(async (context, next) => {
    var clientIp = context.Connection.RemoteIpAddress;
    var rateLimitKey = $"upload:{clientIp}";

    // 简单的Redis计数器(实际用StackExchange.Redis,就像用周黑鸭的真空包装)
    if (redis.Increment(rateLimitKey) > 100) {
    context.Response.StatusCode = 429;
    await context.Response.WriteAsync("慢点,兄弟!武汉话叫'莫慌'!");
    return;
    }
    await next();
    });

  • 异步处理文件合并:// 用Hangfire后台任务(就像让外卖小哥先送其他单)
    _backgroundJobClient.Schedule(
    () => MergeFile(fileHash),
    TimeSpan.FromMinutes(1) // 延迟1分钟合并,给前端时间传完所有分片(就像等公交时先抽根烟)
    );
  • 数据库优化(户部巷方案):

  • 改用SQL Server的FILESTREAM存储大文件元数据(就像把鸭脖真空包装)
  • 添加Redis缓存当前上传任务(就像用美团外卖看哪家热干面排队人少)
  • 对大文件记录采用"软删除"策略(标记为删除但不真删,怕客户反悔,就像你妈说"这碗面你吃不吃?不吃我倒了"但实际不会倒)
  • 分表策略:— 按年份分表(就像把不同季节的衣服分开放)
    CREATE TABLE UploadTasks_2024 (
    — 结构同主表
    );
  • 终幕:测试日的疯狂(光谷限定版)

    当客户终于发来测试文件时,我的监控面板是这样的:

    • IIS错误日志:每分钟新增5条"Connection_Abandoned_By_ReqQueue"(就像每分钟有5个乘客在光谷广场迷路)
    • .NET Core内存占用突破1.8G(就像你试图把整个户部巷的小吃塞进背包)
    • SQL Server:慢查询日志里全是SELECT * FROM UploadTasks WHERE Status=0(就像周末的江汉路,全是找厕所的人)

    但!当那个2.1G的《武汉城市宣传片》终于显示"上传成功"时,我激动得把鸭脖骨头卡在键盘里——至少这次没把服务器宕机,只是让整个办公室的鼠标都变得黏糊糊的(就像光谷步行街的地砖)。

    (客户反馈:IE11下进度条会跳《龙船调》。我:微笑.jpg 并默默在Nginx配置里加了if ($http_user_agent ~* "MSIE") { return 403; },就像武汉公交司机对问路的人说"往那头走,莫问我")

    设置框架

    安装.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 相关参考: 文件保存位置,

    效果预览

    文件上传

    文件上传

    文件刷新续传

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

    文件夹上传

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

    下载完整示例

    下载完整示例

    赞(0)
    未经允许不得转载:网硕互联帮助中心 » 国防领域,asp.net如何处理文件夹上传的安全性问题?
    分享到: 更多 (0)

    评论 抢沙发

    评论前必须登录!