Go 语言需通过自定义 Reader 统计读取字节数、客户端轮询或 WebSocket 推送来实现上传进度反馈;服务端用 sync.Map 存储 uploadID 对应的已读/总量/完成状态,提供 /progress?id=xxx 查询接口。

Go 语言本身不直接提供上传进度回调机制,但可以通过包装 http.Request.Body,配合客户端分块上传(如使用 XMLHttpRequest 或 fetch 的 Upload.onprogress)+ 服务端流式读取 + 实时状态存储,实现文件上传进度的实时反馈。核心在于:**服务端边读边记、客户端定时轮询或用 WebSocket 主动推送**。
1. 服务端:自定义 Reader 记录已读字节数
关键是在解析 multipart 表单时,对每个文件的 io.Reader 做一层封装,实时统计已读数据量。
- 使用
io.TeeReader或自定义Read方法,在每次读取后更新共享的进度结构体(如用sync.Map存储以 uploadID 为 key 的进度) - 为每次上传分配唯一 ID(如 UUID),通过 URL 参数或表单字段传入,便于客户端查询
- 示例片段:
2. 客户端:使用 XMLHttpRequest 或 fetch + onprogress
浏览器原生支持上传过程监听,无需额外库。
- 设置
FormData并添加文件和 uploadID 字段 - 用
XMLHttpRequest.upload.onprogress获取当前上传进度(注意:这是客户端已发出的字节数,非服务端接收完成量;若需服务端确认进度,仍需后端配合) - 更可靠的做法是:上传开始后,启动定时器调用
/api/progress?upload_id=xxx查询服务端记录的实际写入进度
3. 进度状态存储与查询接口
服务端需提供轻量、并发安全的进度暂存和读取能力。
- 推荐使用
sync.Map存储活跃上传任务(适合读多写少场景),key 为 uploadID,value 包含 totalSize(预估或客户端传入)、read(已接收字节数)、done(是否完成)等字段 - 提供 GET 接口如
GET /progress?id=abc123,返回 JSON:{"uploaded": 1256432, "total": 5242880, "percent": 23.97} - 注意清理过期进度(例如上传超时或完成 5 分钟后自动删除)
4. 可选增强:WebSocket 主动推送进度
避免轮询开销,适合大文件或高实时性要求场景。
- 客户端建立 WebSocket 连接并发送 uploadID
- 服务端在 ProgressReader 更新时,通过对应 connection 推送进度消息
- 需维护连接与 uploadID 的映射关系(可用
map[string][]*websocket.Conn+ 读写锁) - 注意连接断开时的重连与状态同步逻辑










