技术解析

golang gin 框架分组路由的原理
0
2021-06-08 14:38:11
idczone

gin 文档中的一个例子

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

	// Simple group: v1
	v1 := router.Group("/v1")
	{
		v1.POST("/login", loginEndpoint)
		v1.POST("/submit", submi国外服务器tEndpoint)
		v1.POST("/read", readEndpoint)
	}

	// Simple group: v2
	v2 := router.Group("/v2")
	{
		v2.POST("/login", loginEndpoint)
		v2.POST("/submit", submitEndpoint)
		v2.POST("/read", readEndpoint)
	}

	router.Run(":8080")
}

router.Group方法源码是这样的:

// Group creates a new router group. You should add all the routes that have common middlewares or the same path prefix.
// For example, all the routes that use a common middleware for authorization could be grouped.
func (group *RouterGroup) Group(relativePath string, handlers ...HandlerFunc) *RouterGroup {
	return &RouterGroup{
		Handlers: group.combineHandlers(handlers),
		basePath: group.calculateAbsolutePath(relativePath),
		engine:   group.engine,
	}
}

从上面的例子看, v1 := router.Group("/v1")创建一个子分组v1, 并且v1.engine中存储了父级的信息, 这时候v1知道它的父级是router. 但是程序的入口是router, 但好像并没有把v1关联给router, 那么router怎么知道v1的存在?

(初学 golang, 请大佬解惑, 谢谢)


我纯 Golang 路人。但是 Gin 用的 Router 是基于 httprouter 的,httprouter 用的是 Radix Tree 。所以一定有一步是把节点加入树里。你再看看源码吧。

router 就是 Engine 对象,源码里面你看不是有 engine: group.engine 吗?

https://github.com/xxjwxc/ginrpc
推荐这个

v1.POST() 和 v2.POST() 才是真正注册 route 的方法,group 只是方便理解和操作

那么 router 怎么知道 v1 的存在?

=======
// Group creates a new router group. You should add all the routes that have common middlewares or the same path prefix.
// For example, all the routes that use a common middleware for authorization could be grouped.
func (group *RouterGroup) Group(relativePath string, handlers ...HandlerFunc) *RouterGroup {
return &RouterGroup{
Handlers: group.combineHandlers(handlers),
basePath: group.calculateAbsolutePath(relativePath),
engine: group.engine,
}
}
源码中把 /v1 用于了 basePath 。
然后从 router.GET() 这个方法开始看,看什么时候用到 basePath (也就是 /v1 )
// GET is a shortcut for router.Handle("GET", path, handle).
func (group *RouterGroup) GET(relativePath string, handlers ...HandlerFunc) IRoutes {
return group.handle( http.MethodGet, relativePath, handlers) //进入
}

func (group *RouterGroup) handle( httpMethod, relativePath string, handlers HandlersChain) IRoutes {
absolutePath := group.calculateAbsolutePath(relativePath) //进入
handlers = group.combineHandlers(handlers)
group.engine.addRoute( httpMethod, absolutePath, handlers)
return group.returnObj()
}
func (group *RouterGroup) calculateAbsolutePath(relativePath string) string {
return joinPaths(group.basePath, relativePath) //这里的 basePath 就是你的 "/v1",如果涉及到多重 group,可能是 /xxx/v1
}

=================
上面应该解答了你的疑问『怎么知道 v1 存在』,在每一次 GET/POST 执行的时候,都会根据之前的 basePath 进行计算。

继续深入,可以看 addRoute() ----> engine.trees 相关。然后就是 1 楼说的 httprouter tree 相关,如何快速查找匹配路由。



谢谢, 明白怎么回事了.

数据地带为您的网站提供全球顶级IDC资源
在线咨询
专属客服