路由方法:HTTP 方法与 Any/NoRoute

本章解决什么问题:路由是 Web 框架的门面。本章把 Gin 注册路由的常用姿势过一遍:按方法注册(GET/POST/PUT/PATCH/DELETE/OPTIONS 等)、任意方法 Any、通用 Handle,以及兜底的 NoRoute 与 NoMethod。

按方法注册

gin 的 Engine 为每种 HTTP 方法提供了同名注册方法,第一个参数是路径,第二个是处理函数(接收 *gin.Context)。方法本身只影响路由树的分支,不做语义强制:

package main

import (
	"net/http"

	"github.com/gin-gonic/gin"
)

func main() {
	r := gin.Default()

	r.GET("/ping", func(c *gin.Context) { c.JSON(200, gin.H{"msg": "pong"}) })
	r.POST("/users", func(c *gin.Context) { c.String(http.StatusCreated, "create") })
	r.PUT("/users/:id", func(c *gin.Context) { c.String(200, "replace") })
	r.PATCH("/users/:id", func(c *gin.Context) { c.String(200, "partial") })
	r.DELETE("/users/:id", func(c *gin.Context) { c.String(200, "delete") })
	r.OPTIONS("/users", func(c *gin.Context) { c.Status(http.StatusNoContent) })
	r.Any("/echo", func(c *gin.Context) { c.String(200, c.Request.Method) })
	r.Handle("GET", "/healthz", func(c *gin.Context) { c.String(200, "ok") })

	r.NoRoute(func(c *gin.Context) {
		c.JSON(http.StatusNotFound, gin.H{"error": "not found"})
	})

	r.Run(":8080")
}

约定俗成的语义是 GET 查询、POST 新增、PUT 全量替换、PATCH 部分更新、DELETE 删除;此外还有 HEAD 方法,可通过 r.HEAD 注册,通常不带响应体。

Any 与 Handle

r.Any("/path", handler) 注册后,任意 HTTP 方法都会命中同一个处理器,适合接口探测、统一入口等场景。r.Handle(method, path, handler) 则把方法名作为参数传入,等价于对应的 r.GET/r.POST 等。

NoRoute 与 NoMethod

当任何方法都匹配不到路径时,命中 r.NoRoute 注册的处理器;路径存在但方法不匹配时,需要先把引擎的 HandleMethodNotAllowed 置为 true,才会走到 r.NoMethod(默认关闭,未匹配时按 404 处理)。这两个处理器是“兜底层”,常在这里统一返回 JSON 格式的错误(见第 20 章)。

关键点

  • 同一路径可分别注册不同方法:GET /users 与 POST /users 互不冲突。
  • 同一方法下重复注册相同路径会在启动期 panic,路由树不允许歧义。
  • 匹配优先级:静态路径高于 :name 参数、再高于 *path 通配(见下一章)。
  • 引擎默认开启尾斜杠修正,访问 /users/ 可能被 301 到 /users,可用 r.RedirectTrailingSlash 控制,细节以官方文档为准。

小结

方法注册、Any、NoRoute/NoMethod 覆盖了“谁来处理这个请求”的三种情况。路径本身还能携带变量,下一章讲 :name 与 *path 动态段。

笔记加载中…