中间件不适合做分片合并后的临时文件清理——因其仅作用于单次请求生命周期,无法处理异步、跨请求、失败重试等场景,且无法感知合并函数内部错误、安全访问动态路径或避免并发竞态;清理必须内聚于合并函数中,用defer或显式分支控制。

为什么中间件不适合做分片合并后的临时文件清理
中间件不是清理临时文件的合适位置——它只负责请求生命周期内的逻辑,而分片合并是异步、跨请求、可能失败后重试的操作。一旦合并失败或校验不通过,你得立刻删掉目标文件和所有分片;但此时 handler 已返回响应,中间件早已退出,无法触发清理动作。
更危险的是:若把清理逻辑塞进某个“合并完成”接口的中间件里,会误判成功时机。比如 io.Copy 写完但 sha256.Sum256 校验失败,中间件看不到这个失败,就跳过清理,留下脏数据。
- 中间件无法感知合并函数内部的错误分支(如校验失败、写入中断)
- 它不能安全访问分片目录路径——这些路径通常由上传时的
identifier动态生成,不在上下文公共字段中 - 并发上传同一文件时,多个请求可能同时尝试清理同一目录,引发 race condition
临时文件清理必须放在合并函数内部
真正安全的清理,必须和合并、校验耦合在同一个函数作用域里,用 defer 或显式 if 分支控制。失败时立刻删,成功时按需保留(比如留 24 小时供断点续传)。
示例结构如下:
os.RemoveAll("/tmp/uploads")
- 每个分片写入前,用
os.OpenFile(path, os.O_CREATE|os.O_WRONLY|os.O_EXCL)确保不会覆盖已有分片 - 合并函数只操作
/tmp/uploads/{identifier}/,绝不碰父级 - 若需长期保留分片(如支持断点续传),不要删目录,改用
os.Chtimes更新 mtime,再由后台定时任务扫描过期目录 - 禁止在 handler 中直接调
c.Request.MultipartReader()后又让中间件去清理——中间件拿不到identifier,根本不知道删哪
清理失败比不清理更危险
如果 os.RemoveAll(tmpDir) 返回 error(比如权限不足、文件被占用),你不能忽略它。此时 tmpDir 里残留了未清理的分片,下次同名上传会覆盖失败,或校验错位。
正确做法是记录错误并报警,而不是静默吞掉:
- 用
os.RemoveAll后检查 err,非nil且非os.IsNotExist时,写日志 + 上报监控 - 不要用
os.RemoveAll做“尽力而为”清理——它要么全删干净,要么明确失败 - 生产环境建议用
filepath.WalkDir配合os.Remove逐个删,并对每个失败项单独处理,避免一个文件卡住整个目录
最常被忽略的一点:清理逻辑写在合并函数里,不代表它就自动可靠。你得确保所有错误出口(包括 panic 恢复)都覆盖到,否则一次 I/O 中断就可能留下永久垃圾。











