Iris 不支持分片上传,需手动实现接收、存储临时块、合并三步;须禁用请求体限制、设置读取超时、用 X-Upload-ID 聚合分片,并通过 X-Chunk-Index 或 Content-Range 标识顺序。

分片上传必须自己处理,Iris 不提供内置支持
Iris 框架本身不封装分片上传逻辑,ctx.FormFile() 只能读取单个完整文件,大文件直接传会触发内存溢出或超时。你得在 HTTP 层手动接收分片、校验、合并——核心是把上传拆成「接收 → 存临时块 → 合并」三步,而不是依赖框架自动组装。
常见错误现象:http: request body too large(没关 MaxRequestBodySize)、context deadline exceeded(没调 ctx.SetReadTimeout())、分片顺序错乱(没传 chunkIndex 或服务端没排序)。
- 每个分片建议控制在 2–10 MB,用
Content-Range或自定义 header(如X-Chunk-Index)标识位置 - 前端必须保证同一文件所有分片携带相同
X-Upload-ID(UUID),服务端靠它聚合分片 - Iris 默认限制请求体为 32MB,需显式设大:
app.Run(iris.Addr(":8080"), iris.WithoutBodyLimit)或用iris.WithPostMaxMemory(200
接收分片时怎么避免重复写和并发冲突
多个分片可能并发到达,直接 os.WriteFile() 到同一路径会覆盖。必须用原子操作或加锁,但更稳妥的是:每个分片存独立临时文件,命名含 uploadID 和 chunkIndex,例如 /tmp/upload_abc123_chunk_5.bin。
关键点:
- 用
os.OpenFile(..., os.O_CREATE|os.O_WRONLY|os.O_EXCL)确保不会覆盖已有分片(O_EXCL在文件存在时返回 error) - 不要用内存缓冲全量读分片,用
io.CopyN(dst, src, chunkSize)流式写入,防止 OOM - 记录每个 uploadID 的已接收分片索引到内存 map 或 Redis(
map[string]map[int]bool),合并前校验是否齐全
示例接收逻辑片段:
func handleUploadChunk(ctx iris.Context) {
uploadID := ctx.Request().Header.Get("X-Upload-ID")
chunkIndex := ctx.URLParamIntDefault("chunk", 0)
chunkPath := fmt.Sprintf("/tmp/%s_chunk_%d.bin", uploadID, chunkIndex)
f, err := os.OpenFile(chunkPath, os.O_CREATE|os.O_WRONLY|os.O_EXCL, 0644)
if os.IsExist(err) {
ctx.StatusCode(409) // Conflict: 分片已存在
return
}
defer f.Close()
_, err = io.CopyN(f, ctx.Request().Body, int64(chunkSize))
if err != nil {
ctx.StatusCode(400)
return
}
}
合并文件时如何保证原子性和完整性
合并不是简单按序 cat,而是逐块 open-read-write,且最终重命名必须原子。否则进程崩溃会导致半成品文件残留,前端续传时无法判断状态。
要点:
- 合并目标路径先写到临时名(如
final_file.bin.part),全部写完再os.Rename()覆盖正式名——Rename在同磁盘下是原子的 - 合并前校验每个分片文件大小是否匹配预期(比如第 n 块应为 chunkSize,最后一块可小于等于)
- 用
sha256对所有分片流式计算总哈希(边读边 xor 或拼接 digest),和前端传来的X-Total-Hash对比,防传输损坏
别跳过校验:用户网络抖动可能导致某分片内容截断,但文件长度没变(TCP 重传掩盖了问题),只校验长度不够。
断点续传靠客户端主动探测,服务端只回答“有没有”
断点续传不是服务端“记住进度”然后推给前端,而是前端在上传前先发个 HEAD 请求问:HEAD /api/resume?upload_id=abc123,服务端查当前 uploadID 下已存哪些 chunkIndex,返回 JSON 列表,前端据此跳过已传分片。
这个接口要快,不能每次扫磁盘目录:
- 用
sync.Map缓存活跃 uploadID 的分片索引(适合短时上传任务) - 长期任务必须落 Redis,key 为
upload:,value 是 sorted set 或 bitsetuploadID:chunks - 记得设 TTL,比如 24 小时后自动清理未完成的 uploadID,避免磁盘被临时文件占满
别让服务端“主动恢复”,那是客户端职责;服务端只做确定性响应——有就是有,没有就是没有,不猜、不补、不假设。











