持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第6天,点击查看活动详情
Engine 引擎对象初始化
我们一般会有两种形式的对象初始化,一个是 gin.New() 另一个是 gin.Default()
- gin/gin.go 209行
Default()其实就是New()之后新加了两个中间件而已
func Default() *Engine {
debugPrintWARNINGDefault()
engine := New()
engine.Use(Logger(), Recovery())
return engine
}
我们来重点看一下New()的实现。
func New() *Engine {
debugPrintWARNINGNew()
engine := &Engine{ // 初始化Engine对象
RouterGroup: RouterGroup{ // 初始化路由组对象
Handlers: nil,
basePath: "/",
root: true, // 设置该路由器组为根节点
},
FuncMap: template.FuncMap{},
RedirectTrailingSlash: true,
// 为true,如果只有/hello的路由存在,会将请求/hello/ 请求重定向到/hello , GET 响应到301, 其他响应到307。
RedirectFixedPath: false,
// 如果找不到路由,尝试修复请求路径。例如 /HELLO 和 /../../HEllo 可以重定向到/hello。
HandleMethodNotAllowed: false,
// 是否对不允许的方法,做对应的响应;开启后,入股用POST方法请求[GET /user] ,请求将由[GET /user]处理
ForwardedByClientIP: true,
RemoteIPHeaders: []string{"X-Forwarded-For", "X-Real-IP"},
TrustedPlatform: defaultPlatform,
UseRawPath: false,
RemoveExtraSlash: false,
UnescapePathValues: true,
MaxMultipartMemory: defaultMultipartMemory,
// 提供给http.Request的ParseMultipartForm方法调用的“maxMerory”参数的值。默认是32MB
trees: make(methodTrees, 0, 9),
// 创建容量为9的redix树切片,对应9种请求方法。
delims: render.Delims{Left: "{{", Right: "}}"},
secureJSONPrefix: "while(1);",
trustedProxies: []string{"0.0.0.0/0", "::/0"},
trustedCIDRs: defaultTrustedCIDRs,
}
engine.RouterGroup.engine = engine
engine.pool.New = func() any {
// 设置 sync.Pool 新建上下文对象函数
return engine.allocateContext()
}
return engine
}
Router路由
1 Group路由器组
r.Group() 可以帮助我们更快归纳某种请求。
- gin/routergroup.go 文件
创建路由组,仅是返回路由组对象,路由组的本质就是一个模板,使用路由组添加路由,省去用户填写相同路径前缀和中间件的步骤
func (group *RouterGroup) Group(relativePath string, handlers ...HandlerFunc) *RouterGroup {
// 返回一个路由组对象
return &RouterGroup{
// 新路由器组继承父路由器组的所有处理器
Handlers: group.combineHandlers(handlers),
basePath: group.calculateAbsolutePath(relativePath),
// 将绝对路径计算成相对路径
engine: group.engine,
}
}
combineHandlers()方法
type HandlersChain []HandlerFunc
func (group *RouterGroup) combineHandlers(handlers HandlersChain) HandlersChain {
finalSize := len(group.Handlers) + len(handlers)
// 将原来的处理器长度加上放入当前需要追加的处理器长度
assert1(finalSize < int(abortIndex), "too many handlers")
// 如果超过了63中间件,这个路由是无法进行一个添加的,太多中间件要处理了。
mergedHandlers := make(HandlersChain, finalSize)
copy(mergedHandlers, group.Handlers)
// 把旧的中间件都拷贝到新创建的切片中
copy(mergedHandlers[len(group.Handlers):], handlers)
// 把新的也追加到这个新的创建的切片中
return mergedHandlers
}
func (group *RouterGroup) calculateAbsolutePath(relativePath string) string {
return joinPaths(group.basePath, relativePath)
// 根据绝对路径进行拼接成相对路径
}
2 GET 路由
路由是怎么进行注册的呢?我们通过GET方法来了解一下是怎么处理的
- gin/routergroup.go
func (group *RouterGroup) GET(relativePath string, handlers ...HandlerFunc) IRoutes {
return group.handle(http.MethodGet, relativePath, handlers)
}
然后我们来看看这个handle()方法
func (group *RouterGroup) handle(httpMethod, relativePath string, handlers HandlersChain) IRoutes {
absolutePath := group.calculateAbsolutePath(relativePath)
// 根据相对路径,计算绝对路径
handlers = group.combineHandlers(handlers)
// 合并处理器(实际上就是将handlers追加到原有的处理器组切片中,作为该路径的处理链)
group.engine.addRoute(httpMethod, absolutePath, handlers)
// 添加路由,涉及radix树添加节点方法。
return group.returnObj()
}