全部版块 我的主页
论坛 经济学论坛 三区 环境经济学
76 0
2025-11-20

“张总,这个需求……可能要加钱。”我抿了一口热干面汤,目光紧锁在电脑屏幕上“支持2G文件批量上传”的需求文档上,汗水顺着汉味十足的T恤领口流淌而下。身为光谷软件园里既懂修理打印机又擅长编写WebAPI的全能型人才,我深刻意识到即将面临的三大挑战:Vue2的兼容性难题、SQL Server的存储压力,以及那个令人头疼的WebUploader——它此时如同一根被热干面汤泡软的筷子,无力地躺在控制台中。

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

“看!它动了!”我激动地指着屏幕,只见上传进度条突然跳至99%,然而下一刻Chrome标签页便变成了一片空白。这个由百度开源的组件仿佛一位行为艺术家:

  • 分片上传?功能可用,但有时会将第13片文件误传到汉口火车站(后来查明原因是Nginx的设置限制了单个文件大小为2MB)。
  • 跨浏览器兼容?在360安全浏览器中,进度条会出现卡顿现象;而在QQ浏览器中,则直接显示“NaN%”。
  • 断点续传?一旦客户重启路由器,所有已上传的分片就会像江汉路一样消失无踪。

最让人头疼的莫过于错误处理:

// 前端神秘代码(武昌方言版)
  uploader.on('error', function(type) {
  if (type === 'F_DUPLICATE') {
    alert('文件已存在,但后端可能没接收到此信息,就像你叫服务员加豆浆他没听见');
  } else {
    console.log('出错啦,但我无法准确描述,就像你问路时对方说"往那边走"');
  }
  });
  

client_max_body_size

第二幕:.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: () => {
          // 这个回调可能会随机触发三次,就像公交车司机说“马上到”
      }
  });
  }
  

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

当客户询问是否可以显示所有上传任务的历史记录时,我凝视着那台仅有8GB内存的云服务器陷入了沉思:

-- 初期设计(天真版本,就像认为光谷步行街周末不会拥堵)
  CREATE TABLE UploadTasks (
  Id UNIQUEIDENTIFIER PRIMARY KEY,
  FileName NVARCHAR(255),
  FileSize BIGINT, -- 2G文件即2147483648字节
  Status INT, -- 0=正在上传 1=完成 2=失败 3=合并中...
  CreatedAt DATETIME2,
  -- 省略了五个关联表的设计,就像制作热干面时省去了萝卜丁
  );
  

直到测试阶段才发现:

  • 插入1000条记录后,查询“正在进行的任务”需要2.8秒(如同等待643路公交车)。
  • 未对相关字段添加索引(别问我如何得知,就像别问为何总是错过地铁末班)。
    FileHash
  • Nginx超时断开连接时,.NET Core依然盲目地继续插入分片记录(就像你举着手机寻找信号时对方已经挂断)。

在合并文件时,

FileStream

直接消耗了4GB的内存(就像尝试一口气吃完一整碗热干面)。

第四幕:生存挑战方案(光谷定制版)

经过连续三天的网络搜索(以及两包精武鸭脖),我制定了一套新的策略:

前端改进计划(汉味优化)

放弃使用WebUploader,转而采用更现代的技术栈:

uppy.io

(确保文档是最新版本,就像武汉公交时刻表一样更新频繁)

实现真正的断点续传功能:

// 使用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.8GB(就像试图将整个户部巷的小吃装进背包)

SQL Server:慢查询日志中充满了:

SELECT * FROM UploadTasks WHERE Status=0

(就像周末的江汉路上,到处都是寻找厕所的人)

然而!当2.1GB大小的《武汉城市宣传片》最终显示“上传成功”时,我激动得将鸭脖骨头卡在了键盘上——至少这次没有导致服务器崩溃,只是使得整个办公室的鼠标变得粘乎乎的(就像光谷步行街的地砖)。

(客户反馈:在IE11浏览器下,进度条会播放《龙船调》。我的反应是微笑,并默默地在Nginx配置中添加了:

if ($http_user_agent ~* "MSIE") { return 403; }

就像武汉公交司机对询问路线的人说“朝那边走,别再问我了”)

环境搭建

安装.NET Framework 4.7.2

下载链接

选择框架版本4.7.2

添加第三方库引用

编译项目

NOSQL

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

SQL

建议使用IIS进行大文件上传测试,以获得更高的性能。

使用IIS Express进行小文件上传测试是可行的。

在开始之前,请确保已创建好数据库。

接下来,配置数据库的连接信息,确保应用程序能够正确访问数据库。

完成配置后,检查数据库设置是否正确无误。

一切就绪后,可以通过访问页面来测试整个流程。

相关参考

  • 文件保存的具体位置
  • 效果预览展示
  • 实现文件上传功能

该系统支持文件的刷新续传,即在关闭或刷新浏览器后,仍能保持文件上传的进度,不会丢失任何上传状态。

此外,还支持上传整个文件夹,并且能够保留文件夹的层级结构。这一特性同样支持进度信息的离线保存,即使刷新页面、关闭页面或重启系统,上传进度也不会丢失。

为了帮助您更好地理解和使用该功能,我们提供了完整的示例供下载。

二维码

扫码加我 拉你入群

请注明:姓名-公司-职位

以便审核进群资格,未注明则拒绝

相关推荐
栏目导航
热门文章
推荐文章

说点什么

分享

扫码加好友,拉您进群
各岗位、行业、专业交流群