中间件函数签名必须是func(*gin.context),否则注册时立即panic;需按cors→recovery→auth→logger顺序注册以确保c.get()取值正确;jwt须显式校验token.valid,读写请求响应体需缓存或包装。

中间件函数签名必须是 func(*gin.Context)
传给 r.Use() 的东西,如果不是 gin.HandlerFunc 类型,Gin 会立刻 panic,错误类似 panic: interface conversion: interface {} is func(), not gin.HandlerFunc。这不是运行时出错,而是注册阶段就崩了。
常见翻车写法:
- 写成带参数的函数,比如
func AuthMiddleware(role string) *gin.Context—— 返回类型不对,签名也不对 - 调用时漏掉括号:
r.Use(AuthMiddleware)(传函数地址)而不是r.Use(AuthMiddleware())(传执行后返回的gin.HandlerFunc) - 用闭包但没显式转成
gin.HandlerFunc,例如r.Use(func(c *gin.Context) {...})是合法的,但若嵌套在其他逻辑里没注意类型推导,可能被 Go 编译器拒绝
安全写法只有一条:中间件定义或调用时,确保最终传入 Use() 的值类型就是 gin.HandlerFunc。最稳的是先定义函数再传名,或用闭包并明确返回类型:
func AuthMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
// ...
c.Next()
}
}
// 然后 r.Use(AuthMiddleware())
中间件顺序决定 c.Get() 能否取到值
你在日志中间件里调 c.Set("user", u),下游却 c.MustGet("user") panic?大概率不是代码写错,而是中间件没按顺序注册。
Gin 的中间件链是“先进后出”(栈式),r.Use(A, B, C) 表示请求先过 C,再 B,最后 A;响应则反过来:A → B → C。所以依赖某个键值的中间件,必须排在设置该键值的中间件之后(即更靠近路由处理器)。
典型正确顺序:
-
Cors()(前置,不依赖上下文) -
Recovery()(兜底,也前置) -
AuthMiddleware()(必须在这里c.Set("user", ...)) -
Logger()(后面才能c.Get("user"))
如果把 Logger() 放在 AuthMiddleware() 前面,c.Get("user") 永远返回 nil。
读请求体或写响应体必须做缓存/包装
直接在中间件里读 c.Request.Body 或断言 c.Writer 为具体类型,99% 会失败。因为 Gin 的 Request.Body 是单次可读流,c.ShouldBindJSON() 会读空它;c.Writer 是接口,底层实际是 responseWriter,不能直接取内容。
想记录原始请求体:
- 先用
io.ReadAll(c.Request.Body)读取字节 - 再用
c.Request.Body = io.NopCloser(bytes.NewBuffer(bodyBytes))回填 - 注意大请求会吃内存,生产环境建议加大小限制
想捕获响应体:
- 必须自定义结构体实现
http.ResponseWriter接口(重写Write()、WriteHeader()) - 把输出先写进
bytes.Buffer,c.Next()后再读缓冲区 - 别试图用
c.Writer.(ResponseWriter).Body()—— Gin 没提供这个方法
JWT 过期检查不能靠签名有效就放过
很多鉴权中间件只校验 JWT 签名,但 token.Claims.(jwt.MapClaims)["exp"] 已过期时,签名仍可能验证通过。Gin 不会自动帮你判断 Valid 字段。
必须显式检查:
if !token.Valid { c.AbortWithStatusJSON(401, gin.H{"error": "token expired"}) }- 别在
c.Next()之后才检查 —— 那时业务 handler 已执行,可能已改数据库 - 别只查
err == nil就认为 token 可用,Parse()成功不代表未过期
一个容易被忽略的点:jwt.Parse() 的第二个参数(keyfunc)返回 key 后,token 对象的 Valid 字段才被计算,必须在这之后立即检查。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











