路由基础 #
一、路由概述 #
1.1 什么是路由 #
路由是将HTTP请求映射到处理函数的机制:
text
HTTP请求 → 路由匹配 → 处理函数 → 响应
1.2 Gin路由特点 #
| 特点 | 说明 |
|---|---|
| 高性能 | 基于httprouter,O(1)时间复杂度 |
| 灵活 | 支持动态参数、通配符 |
| 分组 | 支持路由分组管理 |
| 中间件 | 路由级别中间件支持 |
1.3 路由组成 #
text
路由 = HTTP方法 + 路径 + 处理函数
例如:
GET /users/:id → getUserHandler
二、基本路由注册 #
2.1 创建路由引擎 #
go
package main
import "github.com/gin-gonic/gin"
func main() {
// 创建默认路由引擎(包含Logger和Recovery中间件)
r := gin.Default()
// 创建空白路由引擎(无中间件)
r = gin.New()
r.Run()
}
2.2 注册基本路由 #
go
func main() {
r := gin.Default()
// GET请求
r.GET("/hello", func(c *gin.Context) {
c.String(200, "Hello, Gin!")
})
// POST请求
r.POST("/login", func(c *gin.Context) {
c.JSON(200, gin.H{"message": "login success"})
})
// PUT请求
r.PUT("/update", func(c *gin.Context) {
c.JSON(200, gin.H{"message": "update success"})
})
// DELETE请求
r.DELETE("/delete", func(c *gin.Context) {
c.JSON(200, gin.H{"message": "delete success"})
})
// PATCH请求
r.PATCH("/patch", func(c *gin.Context) {
c.JSON(200, gin.H{"message": "patch success"})
})
// HEAD请求
r.HEAD("/head", func(c *gin.Context) {
c.Status(200)
})
// OPTIONS请求
r.OPTIONS("/options", func(c *gin.Context) {
c.Status(200)
})
r.Run()
}
2.3 匹配所有HTTP方法 #
go
func main() {
r := gin.Default()
// 匹配所有HTTP方法
r.Any("/any", func(c *gin.Context) {
c.JSON(200, gin.H{
"method": c.Request.Method,
"path": c.Request.URL.Path,
})
})
r.Run()
}
2.4 匹配多个方法 #
go
func main() {
r := gin.Default()
handler := func(c *gin.Context) {
c.JSON(200, gin.H{"message": "ok"})
}
// 为同一路径注册多个方法
r.GET("/resource", handler)
r.POST("/resource", handler)
r.PUT("/resource", handler)
r.DELETE("/resource", handler)
r.Run()
}
三、路由处理函数 #
3.1 HandlerFunc类型 #
go
// HandlerFunc是Gin的处理函数类型
type HandlerFunc func(*Context)
// 使用示例
func helloHandler(c *gin.Context) {
c.String(200, "Hello!")
}
r.GET("/hello", helloHandler)
3.2 多个处理函数 #
go
func main() {
r := gin.Default()
// 多个处理函数依次执行
r.GET("/chain",
func(c *gin.Context) {
fmt.Println("第一个处理函数")
c.Next() // 调用下一个处理函数
},
func(c *gin.Context) {
fmt.Println("第二个处理函数")
c.Next()
},
func(c *gin.Context) {
c.String(200, "响应")
},
)
r.Run()
}
3.3 处理函数中断 #
go
func main() {
r := gin.Default()
r.GET("/abort",
func(c *gin.Context) {
fmt.Println("第一个处理函数")
c.Abort() // 中断后续处理函数
fmt.Println("Abort后继续执行当前函数")
},
func(c *gin.Context) {
fmt.Println("不会执行")
},
)
r.Run()
}
3.4 检查是否中断 #
go
func main() {
r := gin.Default()
r.GET("/check-abort",
func(c *gin.Context) {
c.Abort()
},
func(c *gin.Context) {
if c.IsAborted() {
fmt.Println("请求已被中断")
return
}
c.String(200, "ok")
},
)
r.Run()
}
四、路由匹配规则 #
4.1 静态路由 #
go
func main() {
r := gin.Default()
// 精确匹配
r.GET("/users", func(c *gin.Context) {
c.String(200, "用户列表")
})
r.GET("/users/profile", func(c *gin.Context) {
c.String(200, "用户资料")
})
r.Run()
}
4.2 动态参数 #
go
func main() {
r := gin.Default()
// 单个参数
r.GET("/users/:id", func(c *gin.Context) {
id := c.Param("id")
c.String(200, "用户ID: %s", id)
})
// 多个参数
r.GET("/users/:id/posts/:postId", func(c *gin.Context) {
id := c.Param("id")
postId := c.Param("postId")
c.String(200, "用户ID: %s, 文章ID: %s", id, postId)
})
r.Run()
}
4.3 通配符 #
go
func main() {
r := gin.Default()
// *action 匹配所有后续路径
r.GET("/files/*filepath", func(c *gin.Context) {
filepath := c.Param("filepath")
c.String(200, "文件路径: %s", filepath)
})
// 访问 /files/a/b/c.txt → filepath = "/a/b/c.txt"
// 访问 /files/ → filepath = "/"
r.Run()
}
4.4 匹配优先级 #
go
func main() {
r := gin.Default()
// 匹配优先级:静态 > 动态参数 > 通配符
// 最高优先级:静态路由
r.GET("/users/profile", func(c *gin.Context) {
c.String(200, "静态路由")
})
// 中等优先级:动态参数
r.GET("/users/:id", func(c *gin.Context) {
c.String(200, "动态参数")
})
// 最低优先级:通配符
r.GET("/users/*action", func(c *gin.Context) {
c.String(200, "通配符")
})
// /users/profile → "静态路由"
// /users/123 → "动态参数"
// /users/123/abc → "通配符"
r.Run()
}
五、路由信息获取 #
5.1 获取所有路由 #
go
func main() {
r := gin.Default()
r.GET("/users", func(c *gin.Context) {})
r.POST("/users", func(c *gin.Context) {})
r.GET("/users/:id", func(c *gin.Context) {})
// 获取所有路由信息
routes := r.Routes()
for _, route := range routes {
fmt.Printf("Method: %s, Path: %s, Handler: %s\n",
route.Method, route.Path, route.Handler)
}
r.Run()
}
5.2 自定义路由信息 #
go
func main() {
r := gin.Default()
gin.DebugPrintRouteFunc = func(httpMethod, absolutePath, handlerName string, nuHandlers int) {
log.Printf("[ROUTE] %-6s %-30s --> %s (%d handlers)\n",
httpMethod, absolutePath, handlerName, nuHandlers)
}
r.GET("/hello", func(c *gin.Context) {
c.String(200, "Hello")
})
r.Run()
}
六、路由处理技巧 #
6.1 统一响应格式 #
go
type Response struct {
Code int `json:"code"`
Message string `json:"message"`
Data interface{} `json:"data,omitempty"`
}
func Success(c *gin.Context, data interface{}) {
c.JSON(200, Response{
Code: 0,
Message: "success",
Data: data,
})
}
func Error(c *gin.Context, code int, message string) {
c.JSON(200, Response{
Code: code,
Message: message,
})
}
func main() {
r := gin.Default()
r.GET("/success", func(c *gin.Context) {
Success(c, gin.H{"name": "Gin"})
})
r.GET("/error", func(c *gin.Context) {
Error(c, 1001, "参数错误")
})
r.Run()
}
6.2 路由处理函数封装 #
go
type Handler func(c *gin.Context) (interface{}, error)
func Wrap(h Handler) gin.HandlerFunc {
return func(c *gin.Context) {
data, err := h(c)
if err != nil {
c.JSON(500, gin.H{"error": err.Error()})
return
}
c.JSON(200, gin.H{"data": data})
}
}
func main() {
r := gin.Default()
r.GET("/hello", Wrap(func(c *gin.Context) (interface{}, error) {
return gin.H{"message": "Hello"}, nil
}))
r.Run()
}
6.3 请求上下文传递 #
go
func main() {
r := gin.Default()
r.GET("/context",
func(c *gin.Context) {
// 设置上下文值
c.Set("userId", "123")
c.Set("role", "admin")
c.Next()
},
func(c *gin.Context) {
// 获取上下文值
userId, _ := c.Get("userId")
role, _ := c.Get("role")
c.JSON(200, gin.H{
"userId": userId,
"role": role,
})
},
)
r.Run()
}
七、路由调试 #
7.1 打印路由树 #
go
func main() {
r := gin.Default()
r.GET("/users", func(c *gin.Context) {})
r.GET("/users/:id", func(c *gin.Context) {})
r.POST("/users", func(c *gin.Context) {})
// 打印路由信息
routes := r.Routes()
fmt.Println("=== 注册的路由 ===")
for _, route := range routes {
fmt.Printf("%s\t%s\n", route.Method, route.Path)
}
r.Run()
}
7.2 路由冲突检测 #
go
func main() {
r := gin.Default()
// 这两个路由会冲突
r.GET("/users/:id", func(c *gin.Context) {
c.String(200, "ID: %s", c.Param("id"))
})
// panic: conflicts with existing wildcard
// r.GET("/users/:name", func(c *gin.Context) {
// c.String(200, "Name: %s", c.Param("name"))
// })
r.Run()
}
八、总结 #
8.1 核心要点 #
| 要点 | 说明 |
|---|---|
| 路由注册 | r.GET/POST/PUT/DELETE等 |
| 处理函数 | func(c *gin.Context) |
| 动态参数 | :param 获取单个参数 |
| 通配符 | *param 匹配后续所有路径 |
| 匹配优先级 | 静态 > 动态 > 通配符 |
8.2 最佳实践 #
| 实践 | 说明 |
|---|---|
| RESTful设计 | 使用标准HTTP方法 |
| 统一响应 | 封装响应格式 |
| 错误处理 | 统一错误处理 |
| 路由分组 | 按模块分组管理 |
8.3 下一步 #
现在你已经掌握了路由基础,接下来让我们学习 路由参数,深入了解参数获取方式!
最后更新:2026-03-28