gin 严格按显式注册的 http 方法(如 r.get、r.post)匹配请求,不自动推断;方法名错误、路径大小写或尾部斜杠不符均导致 404;参数须用对应方式提取(c.param、c.query、c.shouldbindjson 等),content-type 与解析函数必须一致。

Gin 处理 HTTP 请求方法不是靠“猜”或“试”,而是明确绑定到 r.GET、r.POST 等函数上;用错方法名或混淆语义(比如用 GET 接收 JSON body)会导致 404 或空参数,不是框架 bug,是路由没命中或解析逻辑不匹配。
GET/POST/DELETE 等方法必须显式调用对应函数
Gin 不会自动根据请求体内容推断该走哪个 handler。它只看注册时用的是 r.GET 还是 r.POST,再比对客户端发来的 Request.Method 字符串是否完全一致。
-
r.GET("/user", handler)只响应GET /user,哪怕 POST 同路径也 404 -
r.Any("/debug")才能同时响应所有方法,但会失去语义约束,慎用 -
r.Match([]string{"GET", "HEAD"}, "/health")可组合多个方法,比Any更精准 - 浏览器地址栏输入 URL 默认发 GET,想测 POST 必须用
curl、Postman 或前端fetch
路径参数和查询参数不能混用 c.Param 与 c.Query
URL /user/123?role=admin 中,123 是路径参数,admin 是查询参数——它们存储位置、提取方式、甚至编码规则都不同,强行用错函数会返回空字符串。
-
c.Param("id")只读:id这类路由定义里的占位符,/user/:id才有效;写成/user?id=123就取不到 -
c.Query("role")读?role=xxx,不区分 GET/POST,但 POST 表单里没有 query string,所以 POST 请求中它常为空 -
c.DefaultQuery("page", "1")比c.Query安全,避免判空逻辑散落在各处 - 路径参数不经过 URL 解码(如
%20保持原样),而 query 参数会被自动解码
JSON 和表单数据要用不同的解析方式
Content-Type 决定你该调哪个方法:Gin 不会自动识别 body 类型。设错 header 或用错解析函数,c.ShouldBind 会静默失败或 panic。
- 前端发
Content-Type: application/json→ 必须用c.ShouldBindJSON(&v)或c.BindJSON(&v) - HTML 表单或
curl -F→Content-Type: multipart/form-data→ 用c.ShouldBind(&v)(它会自动选 form 绑定器) -
application/x-www-form-urlencoded→c.PostForm("key")或结构体绑定 - 不要对 JSON body 调用
c.PostForm,它永远返回空;也不要对表单调ShouldBindJSON,会报invalid character -
c.ShouldBind是推荐写法,它统一处理 JSON/form/urlencoded,并支持bindingtag 验证
Handle 是底层接口,GET/POST 是语法糖
r.Handle("GET", "/path", h) 和 r.GET("/path", h) 效果一样,但前者容易手误写错方法名(比如拼成 "GEt"),且丢失 IDE 提示和类型检查。
-
r.GET内部就是调r.Handle("GET", ...),没有性能差异 - 只有需要动态构造 method 字符串(比如从配置加载)时才用
Handle -
r.OPTIONS、r.HEAD这些冷门方法,直接用对应函数更清晰,别硬套Handle - 自定义方法如
PROPFIND才必须用r.Handle("PROPFIND", ...)
最易被忽略的点:Gin 的路由匹配是**严格区分大小写和尾部斜杠**的。/api/users 和 /api/users/ 是两个路由;Get 和 GET 在 Handle 里不等价。这些不是运行时错误,而是请求根本进不了 handler —— 日志里连 trace 都没有,得先确认 curl -v 看实际 method 和 path 是什么。











