Gin 处理七牛云上传回调需用 c.Request.FormValue 或 io.ReadAll(c.Request.Body) 解析非 JSON 请求体,路由必须精确匹配 callbackUrl 并返回纯文本 200 响应,验签须基于原始 body 字节流与 X-Qiniu-Callback-Signature 比对,uploadToken 应动态生成且带合理过期时间。

如何用 Gin 处理七牛云上传回调(callback)
七牛云上传完成后会向你指定的 callbackUrl 发起 POST 请求,Gin 必须能正确接收并解析这个请求体,否则验签失败或数据丢失。关键在于:七牛发的是 application/x-www-form-urlencoded 或原始 application/octet-stream(取决于是否开启 callbackBody),不是标准 JSON。
常见错误是直接用 c.BindJSON(),结果绑定失败、err 为 invalid character 或空结构体。
- 用
c.Request.FormValue("key")或c.Request.PostFormValue("key")读取表单字段(适用于callbackBody为 form 格式) - 若回调体是 raw body(比如七牛传了自定义
callbackBodyType=application/json),需先调用c.Request.Body读一次,再用json.Unmarshal()解析——注意Body只能读一次,别在中间件里提前 consume 掉 - 验签必须用原始 body(未 parse 的字节流),所以建议在 handler 开头就
body, _ := io.ReadAll(c.Request.Body),然后分别用于验签和解析
Gin 路由怎么配才不被七牛拒绝
七牛回调要求 HTTP 状态码必须是 200,且响应体只能是纯文本(如 {"code":0} 或空字符串),不能带 HTML、额外 header(如 X-Content-Type-Options)、或 Gin 默认的 JSON 封装(如 {"code":200,"data":{}})。
典型翻车点:用 c.JSON(200, map[string]interface{}{"code": 0}),七牛认为响应非法,反复重试回调。
立即学习“go语言免费学习笔记(深入)”;
使用 uber-go/dig 在 Golang 中实现依赖注入——基于反射容器,提供 Provide/Invoke、dig.In/dig.Out 参数与结果对象,支持命名依赖等
- 成功响应只写
c.String(200, `{"code":0}`)或c.Status(200)(空响应) - 路由路径必须与七牛控制台配置的
callbackUrl完全一致(含 trailing slash),例如七牛填的是https://api.example.com/qiniu/callback,Gin 就得注册POST /qiniu/callback,不能是/callback/ - 确保该路由没被其他中间件拦截(比如 JWT 验证、CORS preflight 拦截),七牛不带
Authorization头,也不走 OPTIONS 预检
怎么安全验签七牛回调(避免伪造请求)
七牛会在回调请求头里带 X-Qiniu-Callback-Signature,值是 HmacSHA1(callbackBody + "\n" + callbackToken),其中 callbackToken 是你在服务端拼出的 AccessKey:encodedPath:Expires。验签失败就直接 c.AbortWithStatus(401)。
容易忽略的是:callbackBody 必须是原始字节流(未 decode、未 parse),且换行符必须是 \n(不是 \r\n),否则签名对不上。
- 用
qiniuAuth := qiniu.NewMac(accessKey, secretKey)(github.com/qiniu/go-sdk/v7)生成 token 时,path参数要和实际回调路径一致(如/qiniu/callback),且不含域名和 query - 验签前先检查
c.GetHeader("X-Qiniu-Callback-Signature")是否存在,再比对;别用c.Request.URL.Path拼,因为反向代理可能改写 path - 七牛回调默认超时 5 秒,验签+业务处理总耗时别超时,否则会重试(最多 3 次),注意并发写同一 key 的风险
上传凭证(uploadToken)怎么在 Gin 里安全生成
前端不能直接接触 secretKey,所以 uploadToken 必须由 Gin 后端动态生成并返回。别把 token 缓存太久(七牛默认有效期 3600 秒),也别复用同一个 token 给多个用户。
常见坑:用全局变量存 token、或用固定 deadline 导致过期后前端上传失败报 401 Unauthorized。
- 每次请求都调用
putPolicy.PutPolicy().UploadToken(mac),deadline设为time.Now().Add(30 * time.Minute).Unix() - PutPolicy 可设
Scope(限制 bucket 和 key 前缀)、CallbackUrl(强制回调地址)、CallbackBody(回调时 POST 的内容模板),这些必须和服务端回调逻辑匹配 - 返回给前端的字段名要和前端 SDK 期望的一致,比如
uptoken(qiniu-js)或token(qiniu-web),别写成upload_token
七牛回调的 body 结构和签名规则细节多,稍微错一个字符或换行就会验签失败——建议把回调解析和验签逻辑抽成独立函数,加单元测试,别堆在 handler 里。

















