ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

TREK 文件上传队列完全解析:超时控制与大文件上传的 5 层设计

TREK 文件上传队列完全解析:超时控制与大文件上传的 5 层设计 TREK 文件上传队列完全解析超时控制与大文件上传的 5 层设计【免费下载链接】TREKA self-hosted travel/trip planner with real-time collaboration, interactive maps, PWA support, SSO, budgets, packing lists, and more.项目地址: https://gitcode.com/GitHub_Trending/nomad22/TREKTREK 是一个自托管的旅行计划工具支持实时协作、互动地图、PWA、预算和打包清单等功能。其中「文件上传队列」uploadQueue是它处理照片、文档、视频等大文件的核心机制并发 3 路上传、失败自动重试、按字节计算进度、每个文件携带幂等键让 500 MB 的视频备份也能稳定上传到服务器。本文带你从前端队列到后端幂等中间件看懂这套设计的全部 5 层。一、为什么上传会被 8 秒超时打断问题源自一个真实 bug#1495TREK 的全局 axios 实例设置了 8 秒超时client.ts配置项值含义timeout8000 ms整个请求的总时限不是空闲时限withCredentialstrue携带登录 Cookieaxios 的超时是整个请求的截止线而不是没有数据流动的超时。这意味着一张手机照片在弱网下推送超过 8 秒请求就会在半途被掐断服务器端multer 中间件报出Request aborted错误。最初的修复是手动给封面图上传加timeout: 0取消超时结果同样的 bug 在另外 7 个上传接口上复活了——其中包括两个支持500 MB的接口文档上传、备份恢复。 核心教训超时豁免不能靠每个调用点记得写必须收敛到唯一入口成为默认行为。二、第一道防线postMultipart 统一入口所有文件上传现在都必须经过 client.ts 中的postMultipart()函数它做三件事timeout: 0—— 彻底取消请求超时大文件想传多久传多久自动附带幂等键—— 传入idempotencyKey时设置X-Idempotency-Key请求头透传进度回调——onUploadProgress让 UI 实时显示上传百分比。代码注释里写得很直白Every upload therefore has to opt out with timeout: 0... Centralizing makes the correct behavior the default instead of something you have to remember.目前走这个入口的接口覆盖了全部 15 个 multipart 上传点从 5 MB 的头像到 500 MB 的视频测试如何钉死这 15 个接口uploadTimeout.test.ts 用 13 个编号用例FE-API-UPLOAD-001 ~ 013逐一断言每个 multipart 调用都必须以timeout: 0发出。任何一个新接口忘了走postMultipartCI 立刻红灯——这就是把正确行为变成默认的自动化保障。用例接口文件大小上限001头像上传/auth/avatar5 MB002 / 006 / 012行程、旅程、收藏封面20 MB007 / 008旅程照片 / 画廊视频20 MB /500 MB009行程文件/trips/:id/files500 MB011备份恢复/backup/upload-restore500 MB三、第二道防线uploadQueue 弹性上传队列真正管理一批文件上传的是 uploadQueue.ts 中的uploadFilesResilient()它是队列层的核心。设计上有 4 个关键机制1️⃣ 并发 worker 池默认 3 路函数用共享游标idx 多个worker()协程实现取下一个文件就上传下一个的模式默认最多 3 个文件同时在传。既比串行快又不会把上传带宽和服务端 multer 打爆。2️⃣ 按错误性质决定是否重试isRetryable()的判断规则非常克制4xx 错误不重试400~499——请求本身有问题比如文件超上限、格式错误重试一万次也不会成功5xx 和网络错误才重试默认重试 2 次重试采用递增退避第 n 次重试前等待400 × n毫秒避免瞬间重发挤垮弱网。3️⃣ 每个文件一个幂等键重试不会重复入库每次上传前用crypto.randomUUID()生成幂等键并通过X-Idempotency-Key发送。服务端 idempotency.ts 中间件会按「键 用户 方法 路径」四元组查重命中则直接回放缓存的响应。这套机制的意义在于网络抖动导致响应丢失、客户端自动重发同一文件时服务器不会存两份。缓存记录保留 24 小时由调度器定期清理响应体超过 256 KB 则不缓存防止备份接口的大 JSON 撑爆去重表。4️⃣ 按字节加权的全局进度UploadProgress不只是完成 3/10 个文件而是把所有文件的已上传字节数 / 总字节数汇总成百分比——传 2 个 50 MB 大文件时进度条不会在1 个传完时跳一半失败文件也会单独计数并归入failed列表返回。四、第三道防线大文件的预处理队列之外TREK 还针对视频这类超大文件做了浏览器端预处理避免服务端转码videoPoster.ts上传视频前浏览器先用video元素解码抽取一帧画到 canvas 导出为 JPEG 海报图和视频一起上传作为缩略图。若解码失败或 10 秒内无响应海报置空继续上传绝不让预处理阻塞主流程journeyStore.ts旅程相册的uploadPhotos/uploadGalleryPhotos直接复用uploadFilesResilient()上传成功后乐观更新本地 storeUI 秒级展示新照片。服务端则按扩展名区分限制视频扩展名适用500 MB上限其他文件另有限制避免一刀切误伤见 files.controller.ts 的注释。五、总结5 层防线一图流层级位置职责① 超时豁免client.tspostMultipart()上传请求统一timeout: 0② 回归测试uploadTimeout.test.ts钉死全部 15 个上传接口③ 弹性队列uploadQueue.ts3 路并发、4xx 不重试、退避重试、字节进度④ 服务端幂等idempotency.ts重放缓存响应杜绝重复入库⑤ 客户端预处理videoPoster.ts浏览器抽帧生成海报免服务端转码给开发者的启示TREK 的上传体系最值得借鉴的不是某个具体参数而是把默认值改对 用测试钉死的方法论——超时豁免收敛进唯一入口再让 CI 保证没人能绕过它。这套思路同样适用于任何需要处理大文件上传的项目。【免费下载链接】TREKA self-hosted travel/trip planner with real-time collaboration, interactive maps, PWA support, SSO, budgets, packing lists, and more.项目地址: https://gitcode.com/GitHub_Trending/nomad22/TREK创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表