gin 的 post /register 接口收不到 json 数据,是因为默认不自动解析 application/json 请求体,必须显式调用 c.shouldbindjson(&req);需确保请求头含 content-type: application/json、payload 为合法 json、结构体字段导出且带 json:"xxx" 标签。

为什么 Gin 的 POST /register 接口收不到 JSON 数据?
默认情况下,Gin 不自动解析 Content-Type: application/json 的请求体,必须显式调用 c.ShouldBindJSON() 或提前注册绑定器。常见现象是 c.PostForm("name") 返回空、c.GetRawData() 能读到原始字节但结构体字段全零值。
- 确保前端请求头带
Content-Type: application/json,且 payload 是合法 JSON(如{"name":"张三","id_card":"110..."}) - 后端必须用
c.ShouldBindJSON(&req),不能只靠c.DefaultPostForm()或c.Query() - 结构体字段需导出(首字母大写),并加
jsontag,例如:type RegisterReq struct { Name string `json:"name"` IDCard string `json:"id_card"` } - 若用
c.BindJSON(),出错会直接返回 400;ShouldBindJSON()允许你自定义错误处理(比如记录日志后再返回 400)
挂号并发冲突:多个请求同时抢同一个号源怎么防?
医院号源是典型“库存扣减”场景,单纯靠数据库 SELECT + UPDATE 在高并发下必然超挂。Gin 本身不提供锁机制,得靠底层保障原子性。
Go 配置库,使用 spf13/viper — 分层优先级(flag > env >file > KV > default),提供 BindPFlag/BindPFlags、SetEnvPrefix + SetEnvKeyReplace 等功能。
- 推荐在 PostgreSQL 中用
UPDATE ... WHERE available_count > 0 RETURNING id,配合行级锁;MySQL 则用SELECT ... FOR UPDATE加事务包裹 - 避免在 Go 层用
sync.Mutex或map做内存锁——它只对单实例有效,集群部署时完全失效 - 号源表建议增加
version字段,用乐观锁重试(最多 2–3 次),比悲观锁吞吐更高 - 注意:Gin 的中间件里别放耗时 DB 查询,否则阻塞整个路由树;挂号核心逻辑应尽量轻量,验证放前面,扣减放最后
如何让 GET /schedule?date=2024-06-15&dept_id=3 支持缓存又不缓存敏感数据?
排班信息变化频率低,但患者挂号记录绝对不能缓存。Gin 默认不带 HTTP 缓存控制,要手动设 Header。
- 对公开排班接口,在 handler 结尾加:
c.Header("Cache-Control", "public, max-age=3600")(缓存 1 小时) - 对含用户身份的接口(如
GET /user/appointments),必须设:c.Header("Cache-Control", "no-store")或"private, no-cache" - 别依赖反向代理(如 Nginx)自动缓存——它无法区分 query 参数语义,
?date=2024-06-15和?date=2024-06-16必须视为不同资源 - 如果用了 Redis 缓存排班结果,key 应包含
dept_id和date,例如:schedule:dept:3:date:2024-06-15
Gin 日志里看不到真实客户端 IP,只看到 127.0.0.1 或负载均衡内网地址
医院系统通常部署在 Nginx 或 SLB 后面,Gin 默认从 RemoteAddr 取 IP,拿到的是上游代理地址。
- 启用 Gin 的信任代理:调用
gin.SetMode(gin.ReleaseMode)后,再执行r.ForwardedByClientIP = true和r.TrustedPlatform = gin.PlatformCloudflare(或自定义r.TrustedProxies = []string{"10.0.0.0/8", "172.16.0.0/12"}) - 确保 Nginx 配置了
proxy_set_header X-Real-IP $remote_addr;和proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - 取 IP 时统一用
c.ClientIP(),不要用c.Request.RemoteAddr - 注意:若医院内网有多个跳转代理,
X-Forwarded-For可能被伪造,生产环境务必校验TrustedProxies列表
X-Real-IP 在混合云环境下的多层代理识别,才是压测阶段最常翻车的地方。golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!










