路由基础 #

一、路由概述 #

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