GoFiber需手动处理Range请求实现视频流与断点续传:解析Range头,返回206状态及Content-Range头,用os.Open+io.LimitReader流式传输;分片上传须禁用MultipartForm自动解析,按upload_id和chunk_index持久化临时文件,避免并发写冲突。

GoFiber 本身不内置断点续传或视频流播放逻辑,但能高效支撑这两类功能的底层实现——关键在正确处理 HTTP Range 请求、分片上传状态管理,以及避免阻塞式文件读写。
如何用 GoFiber 处理视频流的 Range 请求
浏览器播放大视频时会发 Range: bytes=0-1023 这类请求,服务端必须返回 206 Partial Content 及对应头信息,否则播放器卡住或重载全量。
- 不能直接用
c.SendFile():它默认返回200 OK,且不解析Range头 - 必须手动读取文件偏移、设置
Content-Range、Accept-Ranges和Content-Length - 推荐用
os.Open()+io.CopyN()流式转发,避免内存加载整段视频
app.Get("/video/:name", func(c *fiber.Ctx) error {
filename := c.Params("name")
file, err := os.Open("./videos/" + filename)
if err != nil {
return c.Status(404).SendString("not found")
}
defer file.Close()
<pre class="brush:php;toolbar:false;">stat, _ := file.Stat()
size := stat.Size()
rangeHeader := c.Get("Range")
if rangeHeader == "" {
c.Set("Accept-Ranges", "bytes")
c.Set("Content-Length", fmt.Sprintf("%d", size))
c.Set("Content-Type", "video/mp4")
return c.Status(200).SendStream(file)
}
// 解析 Range: bytes=1000-2000
var start, end int64
fmt.Sscanf(rangeHeader, "bytes=%d-%d", &start, &end)
if end == 0 {
end = size - 1
}
c.Set("Accept-Ranges", "bytes")
c.Set("Content-Range", fmt.Sprintf("bytes %d-%d/%d", start, end, size))
c.Set("Content-Length", fmt.Sprintf("%d", end-start+1))
c.Set("Content-Type", "video/mp4")
file.Seek(start, 0)
return c.Status(206).SendStream(io.LimitReader(file, end-start+1))})
GoFiber 实现分片上传与断点续传的关键点
断点续传不是“框架自动支持”的功能,而是靠客户端分片 + 服务端按 upload_id 和 chunk_index 持久化状态来协同完成。
- 每个上传需分配唯一
upload_id(如 UUID),由前端首次请求获取并后续所有分片携带 - 服务端收到分片后,应写入临时路径:
/tmp/upload_${upload_id}_${chunk_index}.part,而非合并到最终文件 - 上传完成前,用
redis或本地 JSON 文件记录已接收的chunk_index集合,供客户端查询“缺哪些片” - 切忌用
multipart.FormFile直接解析整个表单——大文件会吃光内存;改用c.MultipartForm()并逐个Read()分片流
为什么 Fiber 的中间件不适合直接挂起上传流程
Fiber 的 Next() 是同步调用链,ctx.Locals 无法跨请求持久化状态。想在上传中途暂停(比如等用户确认),不能靠 Fiber 中间件“拦住”,而要靠协议层设计:
- 暂停/恢复动作应由前端控制:暂停时停止发送后续分片;恢复时从上次
chunk_index + 1继续 - 服务端不做“挂起 Fiber”,只做幂等写入:重复提交同一
chunk_index应忽略或校验 CRC 后跳过 - 若真需要协程式等待(如异步校验后回调),得用外部事件系统(Redis Pub/Sub)或轮询接口,而不是依赖 Fiber 生命周期
最易被忽略的是文件锁和并发写入竞争:多个分片同时写同一个临时文件(哪怕不同 offset)在 NFS 或某些容器卷上可能出错;务必为每个分片生成独立临时文件,合并阶段再用 cat 或 io.Copy 顺序拼接。











