路由基础 #
一、路由概述 #
路由是将HTTP请求映射到处理函数的机制。Echo使用基于基数树(Radix Tree)的高性能路由实现。
1.1 路由组成 #
text
┌─────────────────────────────────────────────────────────┐
│ 路由组成 │
├─────────────────────────────────────────────────────────┤
│ HTTP方法 + 路径 + 处理函数 = 路由 │
│ │
│ GET /users/:id → getUserHandler │
│ POST /users → createUserHandler │
│ PUT /users/:id → updateUserHandler │
│ DELETE /users/:id → deleteUserHandler │
└─────────────────────────────────────────────────────────┘
1.2 路由特点 #
| 特点 | 说明 |
|---|---|
| 高性能 | 基于基数树,零内存分配 |
| 支持参数 | 路径参数、查询参数 |
| 路由分组 | 支持路由前缀分组 |
| 中间件 | 支持路由级别中间件 |
二、基本路由 #
2.1 注册路由 #
go
package main
import (
"net/http"
"github.com/labstack/echo/v4"
)
func main() {
e := echo.New()
e.GET("/", func(c echo.Context) error {
return c.String(http.StatusOK, "GET /")
})
e.POST("/", func(c echo.Context) error {
return c.String(http.StatusOK, "POST /")
})
e.PUT("/", func(c echo.Context) error {
return c.String(http.StatusOK, "PUT /")
})
e.DELETE("/", func(c echo.Context) error {
return c.String(http.StatusOK, "DELETE /")
})
e.PATCH("/", func(c echo.Context) error {
return c.String(http.StatusOK, "PATCH /")
})
e.OPTIONS("/", func(c echo.Context) error {
return c.String(http.StatusOK, "OPTIONS /")
})
e.HEAD("/", func(c echo.Context) error {
return c.NoContent(http.StatusOK)
})
e.Start(":8080")
}
2.2 Any方法 #
注册所有HTTP方法:
go
e.Any("/any", func(c echo.Context) error {
return c.String(http.StatusOK, "Any method")
})
2.3 Match方法 #
注册指定方法:
go
e.Match([]string{http.MethodGet, http.MethodPost}, "/match", func(c echo.Context) error {
return c.String(http.StatusOK, "GET or POST")
})
三、路径匹配 #
3.1 静态路径 #
go
e.GET("/users", getUsers)
e.GET("/users/profile", getProfile)
e.GET("/users/settings", getSettings)
3.2 路径参数 #
使用 :param 定义路径参数:
go
e.GET("/users/:id", func(c echo.Context) error {
id := c.Param("id")
return c.String(http.StatusOK, "User ID: "+id)
})
测试:
bash
curl http://localhost:8080/users/123
User ID: 123
3.3 多个路径参数 #
go
e.GET("/users/:userId/posts/:postId", func(c echo.Context) error {
userId := c.Param("userId")
postId := c.Param("postId")
return c.String(http.StatusOK, "User: "+userId+", Post: "+postId)
})
测试:
bash
curl http://localhost:8080/users/1/posts/100
User: 1, Post: 100
3.4 通配符参数 #
使用 * 匹配任意路径:
go
e.GET("/files/*", func(c echo.Context) error {
path := c.Param("*")
return c.String(http.StatusOK, "File path: "+path)
})
测试:
bash
curl http://localhost:8080/files/docs/readme.md
File path: docs/readme.md
3.5 可选参数 #
Echo不直接支持可选参数,可以通过注册多个路由实现:
go
e.GET("/search", search)
e.GET("/search/:keyword", search)
func search(c echo.Context) error {
keyword := c.Param("keyword")
if keyword == "" {
keyword = c.QueryParam("q")
}
return c.String(http.StatusOK, "Search: "+keyword)
}
四、路由优先级 #
4.1 匹配规则 #
Echo按以下优先级匹配路由:
text
1. 静态路径(最高优先级)
2. 路径参数
3. 通配符(最低优先级)
4.2 示例说明 #
go
e.GET("/users/profile", getProfile)
e.GET("/users/:id", getUser)
e.GET("/users/*", getAllUsers)
匹配结果:
| 请求路径 | 匹配路由 | 说明 |
|---|---|---|
| /users/profile | /users/profile | 静态路径优先 |
| /users/123 | /users/:id | 参数匹配 |
| /users/admin/settings | /users/* | 通配符匹配 |
4.3 冲突检测 #
Echo会在启动时检测路由冲突:
go
e.GET("/users/:id", getUser)
e.GET("/users/:name", getByName)
启动时报错:
text
echo: path conflict at /users/:name
五、路由信息 #
5.1 获取路由列表 #
go
e := echo.New()
e.GET("/", home)
e.GET("/users", getUsers)
e.GET("/users/:id", getUser)
for _, r := range e.Routes() {
fmt.Printf("%s %s\n", r.Method, r.Path)
}
输出:
text
GET /
GET /users
GET /users/:id
5.2 路由信息结构 #
go
type Route struct {
Method string `json:"method"`
Path string `json:"path"`
Name string `json:"name"`
}
5.3 命名路由 #
go
e.GET("/users/:id", getUser).Name = "getUser"
url := e.Reverse("getUser", "123")
fmt.Println(url)
输出:
text
/users/123
六、路由分组 #
6.1 基本分组 #
go
g := e.Group("/api/v1")
g.GET("/users", getUsers)
g.GET("/users/:id", getUser)
g.POST("/users", createUser)
等价于:
go
e.GET("/api/v1/users", getUsers)
e.GET("/api/v1/users/:id", getUser)
e.POST("/api/v1/users", createUser)
6.2 嵌套分组 #
go
api := e.Group("/api")
v1 := api.Group("/v1")
v1.GET("/users", getUsers)
v1.GET("/posts", getPosts)
v2 := api.Group("/v2")
v2.GET("/users", getUsersV2)
v2.GET("/posts", getPostsV2)
6.3 分组中间件 #
go
api := e.Group("/api", middleware.Logger())
api.GET("/users", getUsers)
auth := api.Group("/auth", middleware.JWT([]byte("secret")))
auth.GET("/profile", getProfile)
七、路由处理函数 #
7.1 HandlerFunc类型 #
go
type HandlerFunc func(Context) error
7.2 返回错误 #
go
e.GET("/error", func(c echo.Context) error {
return echo.NewHTTPError(http.StatusBadRequest, "参数错误")
})
7.3 自定义错误处理 #
go
e.HTTPErrorHandler = func(err error, c echo.Context) {
code := http.StatusInternalServerError
msg := "Internal Server Error"
if he, ok := err.(*echo.HTTPError); ok {
code = he.Code
msg = he.Message.(string)
}
c.JSON(code, map[string]interface{}{
"code": code,
"message": msg,
})
}
八、路由限制 #
8.1 路由数量 #
Echo没有路由数量限制,但建议:
- 单个应用路由数 < 1000
- 使用分组组织路由
- 避免过于复杂的路由结构
8.2 路径长度 #
- 最大路径长度:无限制
- 建议路径长度 < 200字符
8.3 参数数量 #
- 单个路由参数数量:无限制
- 建议参数数量 < 10
九、路由调试 #
9.1 打印路由表 #
go
func printRoutes(e *echo.Echo) {
fmt.Println("\nRegistered Routes:")
fmt.Println("==================")
for _, r := range e.Routes() {
fmt.Printf("%-6s %s\n", r.Method, r.Path)
}
}
9.2 路由中间件 #
go
e.Use(func(next echo.HandlerFunc) echo.HandlerFunc {
return func(c echo.Context) error {
fmt.Printf("Route: %s %s\n", c.Request().Method, c.Path())
return next(c)
}
})
十、完整示例 #
go
package main
import (
"fmt"
"net/http"
"github.com/labstack/echo/v4"
)
func main() {
e := echo.New()
e.GET("/", func(c echo.Context) error {
return c.String(http.StatusOK, "Home")
})
api := e.Group("/api/v1")
{
users := api.Group("/users")
{
users.GET("", listUsers)
users.GET("/:id", getUser)
users.POST("", createUser)
users.PUT("/:id", updateUser)
users.DELETE("/:id", deleteUser)
}
posts := api.Group("/posts")
{
posts.GET("", listPosts)
posts.GET("/:id", getPost)
posts.GET("/:id/comments", getComments)
}
}
e.GET("/files/*", func(c echo.Context) error {
return c.String(http.StatusOK, "File: "+c.Param("*"))
})
printRoutes(e)
e.Start(":8080")
}
func printRoutes(e *echo.Echo) {
fmt.Println("\nRegistered Routes:")
fmt.Println("==================")
for _, r := range e.Routes() {
fmt.Printf("%-6s %s\n", r.Method, r.Path)
}
}
func listUsers(c echo.Context) error {
return c.JSON(http.StatusOK, []string{"user1", "user2"})
}
func getUser(c echo.Context) error {
return c.JSON(http.StatusOK, map[string]string{"id": c.Param("id")})
}
func createUser(c echo.Context) error {
return c.JSON(http.StatusCreated, map[string]string{"status": "created"})
}
func updateUser(c echo.Context) error {
return c.JSON(http.StatusOK, map[string]string{"id": c.Param("id")})
}
func deleteUser(c echo.Context) error {
return c.NoContent(http.StatusNoContent)
}
func listPosts(c echo.Context) error {
return c.JSON(http.StatusOK, []string{"post1", "post2"})
}
func getPost(c echo.Context) error {
return c.JSON(http.StatusOK, map[string]string{"id": c.Param("id")})
}
func getComments(c echo.Context) error {
return c.JSON(http.StatusOK, map[string]string{"postId": c.Param("id")})
}
十一、总结 #
路由基础要点:
| 概念 | 说明 |
|---|---|
| HTTP方法 | GET、POST、PUT、DELETE、PATCH等 |
| 静态路径 | 精确匹配,优先级最高 |
| 路径参数 | :param 定义,动态匹配 |
| 通配符 | * 匹配任意路径 |
| 路由分组 | Group() 组织路由 |
| 路由优先级 | 静态 > 参数 > 通配符 |
准备好学习路由方法了吗?让我们进入下一章!
最后更新:2026-03-28