4. 路由分组
...大约 2 分钟
1. 路由分组
分组控制(Group Control)是 Web 框架应提供的基础功能之一。
若不进行路由分组,那么就需要针对每一个路由分别进行设置和操作。
对路由进行分组的好处:
- 统一管理同一组的路由
- 实现路由组嵌套,不同的子路由可以使用单独的中间件,也可以共享父路由的中间件
通过分组和中间件的组合,提高了系统的可扩展性。
2. 实现
https://github.com/dreamjz/golang-notes/tree/main/books/7-days-golang/Gee/day4-router-group
当前项目结构:
DAY4-ROUTER-GROUP
│ go.mod
│ go.work
│ main.go
│
└─gee
context.go
gee.go
go.mod
router.go
router_group.go
router_test.go
trie.go
2.1 router_group
路由分组需要实现的功能:
- 添加子分组,通过当前分组创建子分组
- 注册路由,可以为当前分组注册路由
路由分组的数据结构如下:
type RouterGroup struct {
prefix string // 路由组前缀
middlewares []HandlerFunc // 中间件
parent *RouterGroup // 父母分组
engine *Engine // 所有分组持有同一个 Engine 实例
}
prefix
:当前路由的前缀middlewares
:中间件函数列表parent
:父母分组,用于分组嵌套engine
:所有的分组持有同一个Engine
实例,那么RouterGroup
就具备Engine
的所有功能,如注册路由
2.2 gee
所有的路由分组组成一个树形结构,所有的节点拥有一个指向其父母节点的指针。
Engine
可以视作树的根节点,此时Engine
与路由相关的功能就交给RouterGroup
实现。
type Engine struct {
*RouterGroup
router *router
groups []*RouterGroup // store all groups
}
groups
:Engine
实例存储所有的分组
2.3 router_group
package gee
import "log"
type RouterGroup struct {
prefix string // 路由组前缀
middlewares []HandlerFunc // 中间件
parent *RouterGroup // 父母分组
engine *Engine // 所有分组持有同一个 Engine 实例
}
// Group create a new RouterGroup
func (group *RouterGroup) Group(prefix string) *RouterGroup {
engine := group.engine
newGroup := &RouterGroup{
prefix: group.prefix + prefix,
parent: group,
engine: engine, // All group share one Engine instance
}
// Add to group lists
engine.groups = append(engine.groups, newGroup)
return newGroup
}
func (group *RouterGroup) addRoute(method string, path string, handler HandlerFunc) {
pattern := group.prefix + path
log.Printf("Route %4s - %s", method, pattern)
group.engine.router.addRoute(method, pattern, handler)
}
func (group *RouterGroup) GET(pattern string, handler HandlerFunc) {
group.addRoute("GET", pattern, handler)
}
func (group *RouterGroup) POST(pattern string, handler HandlerFunc) {
group.addRoute("POST", pattern, handler)
}
3. Demo
func main() {
r := gee.New()
r.GET("/index", func(c *gee.Context) {
c.HTML(http.StatusOK, "<h1>Index Page</h1>")
})
v1 := r.Group("/v1")
{
v1.GET("/", func(c *gee.Context) {
c.HTML(http.StatusOK, "<h1>Welcome v1</h1>")
})
v1.GET("/hello", func(c *gee.Context) {
c.String(http.StatusOK, "Hello %s, you're at %s\n", c.Query("name"), c.Path)
})
}
v2 := r.Group("/v2")
{
v2.GET("/hello/:name", func(c *gee.Context) {
c.String(http.StatusOK, "Hello %s, you're at %s\n", c.Param("name"), c.Path)
})
}
r.Run(":8000")
}
$ curl http://localhost:8000/v1/hello?name=alice
Hello alice, you're at /v1/hello
$ curl http://localhost:8000/v2/
404 NOT FOUND: /v2/
$ curl http://localhost:8000/v2/hello/alice
Hello alice, you're at /v2/hello/alice
Reference
Powered by Waline v2.15.2