绝大多数场景下应使用gin.Default();它默认加载Logger和Recovery中间件,提供请求日志与panic恢复能力,是开发与生产环境的基础安全兜底,而gin.New()需手动添加中间件,仅适用于需精细控制中间件顺序或明确禁用默认行为的特殊场景。

gin.Default() 和 gin.New() 到底该用哪个
绝大多数场景下,直接用 gin.Default() 就行;只有当你需要完全控制中间件加载顺序、或明确禁用日志/panic 恢复时,才考虑 gin.New()。
默认引擎自带 Logger 和 Recovery 两个中间件:前者打请求日志,后者捕获 panic 防止服务崩溃。这正是生产环境最基础的安全兜底。
-
gin.Default()内部就是gin.New()+r.Use(gin.Logger(), gin.Recovery()) - 用
gin.New()后必须手动加r.Use(...),否则连 500 panic 都不会 recover,请求直接挂掉 - 测试或极简 demo 可用
gin.New(),但上线前务必补全必要中间件
中间件执行顺序为什么总出错
中间件不是“注册完就生效”,而是按 Use() 调用顺序串成链,且遵循“洋葱模型”:请求进来时从左到右执行,响应返回时从右到左执行。
常见错误是把鉴权中间件放在路由注册之后,导致它根本没被调用。正确做法是:全局中间件在 r.Use() 中注册,局部中间件绑定在 router.Group().Use() 上。
立即学习“go语言免费学习笔记(深入)”;
Go 配置库,使用 spf13/viper — 分层优先级(flag > env >file > KV > default),提供 BindPFlag/BindPFlags、SetEnvPrefix + SetEnvKeyReplace 等功能。
- 日志中间件应放最外层,保证所有请求都被记录
- 鉴权中间件必须在业务 handler 前执行,且要用
c.AbortWithStatusJSON()终止链,不能只 return - 如果用了
c.Next()却忘了写后续逻辑,请求会卡住——因为流程停在了中间件里
参数绑定时 struct tag 写错导致解析失败
Gin 的 c.ShouldBind() 系列函数依赖 struct tag,比如 json、form、uri,写错或漏写就会静默失败(返回空值或零值),而不是报错。
典型陷阱是 POST JSON 请求用了 c.ShouldBind(&v),但 struct 字段没加 json:"xxx" tag,或者字段名首字母小写导致不可导出,结果 v 全是零值。
- GET 查询参数用
formtag:type Query struct { Page int `form:"page"` } - URL 路径参数用
uritag:type Param struct { ID string `uri:"id"` } - JSON body 必须用
jsontag,且字段首字母大写 - 建议统一用
c.ShouldBindJSON()/c.ShouldBindQuery()显式指定类型,避免歧义
生产环境启动时 panic 报错 “You trusted all proxies”
这是 Gin 的安全警告,不是致命错误,但必须处理。默认 gin.Default() 信任所有代理 IP,意味着攻击者可伪造 X-Forwarded-For 头绕过限流或鉴权。
真实部署中,反向代理(如 Nginx)通常只有一层或有限几层,必须显式配置可信 IP 段,否则 c.ClientIP() 返回的永远是代理地址而非真实客户端 IP。
- 设置
r.SetTrustedProxies([]string{"10.0.0.0/8", "192.168.0.0/16"}) - 若用云厂商 SLB 或 Kubernetes Ingress,查清其出口 IP 段再填入
- 本地开发可设为
r.SetTrustedProxies(nil)关闭校验,但上线前必须改回
这个配置容易被忽略,直到某天发现所有日志里的 client IP 都是同一个内网地址,才意识到问题。

















