雪花还在飘落,浓雾还没散去,我仍然在行走。我在疲惫里越走越深,我想坐下来,然后就坐下了。我不知道是坐在椅子里,还是坐在石头上。我的身体摇摇晃晃坐在那里,像是超重的货船坐在波动的水面上。------《第七天》
官方案例
AsciiJSON
Using AsciiJSON to Generates ASCII-only JSON with escaped non-ASCII characters.
go
func main() {
r := gin.Default()
r.GET("/someJSON", func(c *gin.Context) {
data := map[string]interface{}{
"lang": "GO语言",
"tag": "<br>",
}
// will output : {"lang":"GO\u8bed\u8a00","tag":"\u003cbr\u003e"}
c.AsciiJSON(http.StatusOK, data)
})
// Listen and serve on 0.0.0.0:8080
r.Run(":8080")
}
将其放入代码进行调试
源码执行流程
graph LR
案例-->Gin.Default
Gin.Default--> New
Gin.Default--> engine.Use
Gin.Default--> engine.With
案例--> r.GET --> group.handle
group.handle --> group.calculateAbsolutePath --> joinPaths
group.handle --> group.combineHandlers
group.handle --> group.engine.addRoute --> root.addRoute
案例--> r.Run
r.Run --> resolveAddress
r.Run --> http.ListenAndServe
Default
打入断点,当函数 Default
执行后,r
变量返回了一个 *gin.Engine
进入 Default
函数,函数返回一个 *Engine
,函数返回结果是 `engine.With(opts...)
go
func Default(opts ...OptionFunc) *Engine {
debugPrintWARNINGDefault()
engine := New()
engine.Use(Logger(), Recovery())
return engine.With(opts...)
}
New
可以看到,engine
是通过 New
函数创建的
go
func New(opts ...OptionFunc) *Engine {
debugPrintWARNINGNew()
engine := &Engine{
RouterGroup: RouterGroup{
Handlers: nil,
basePath: "/",
root: true,
},
FuncMap: template.FuncMap{},
RedirectTrailingSlash: true,
RedirectFixedPath: false,
HandleMethodNotAllowed: false,
ForwardedByClientIP: true,
RemoteIPHeaders: []string{"X-Forwarded-For", "X-Real-IP"},
TrustedPlatform: defaultPlatform,
UseRawPath: false,
RemoveExtraSlash: false,
UnescapePathValues: true,
MaxMultipartMemory: defaultMultipartMemory,
trees: make(methodTrees, 0, 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 {
return engine.allocateContext(engine.maxParams)
}
return engine.With(opts...)
}
func (engine *Engine) With(opts ...OptionFunc) *Engine {
for _, opt := range opts {
opt(engine)
}
return engine
}
来到 New
函数实现可以看到,它创建了一个新的 Engine
,将 engine 中的属性 RouterGroup.engine
指向自己,最后返回 engine.With(opts...)
engine.Use
将全局中简介添加到 group.Handlers 上
go
func (group *RouterGroup) Use(middleware ...HandlerFunc) IRoutes {
group.Handlers = append(group.Handlers, middleware...)
return group.returnObj()
}
engine.With
go
func (engine *Engine) With(opts ...OptionFunc) *Engine {
for _, opt := range opts {
opt(engine)
}
return engine
}
r.GET
go
func (group *RouterGroup) GET(relativePath string, handlers ...HandlerFunc) IRoutes {
return group.handle(http.MethodGet, relativePath, handlers)
}
group.handle
go
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()
}
这里关键在于 group.engine.addRoute(httpMethod, absolutePath, handlers)
可以看到按照例子执行后,此时 absolutePath
值为 /someJSON
addRoute
go
func (engine *Engine) addRoute(method, path string, handlers HandlersChain) {
assert1(path[0] == '/', "path must begin with '/'")
assert1(method != "", "HTTP method can not be empty")
assert1(len(handlers) > 0, "there must be at least one handler")
debugPrintRoute(method, path, handlers)
root := engine.trees.get(method)
if root == nil {
root = new(node)
root.fullPath = "/"
engine.trees = append(engine.trees, methodTree{method: method, root: root})
} root.addRoute(path, handlers)
if paramsCount := countParams(path); paramsCount > engine.maxParams {
engine.maxParams = paramsCount
}
if sectionsCount := countSections(path); sectionsCount > engine.maxSections {
engine.maxSections = sectionsCount
}
}
进入 addRoute 后,重点在 engine.trees
的处理,处理完毕后的 trees 为:
执行完成后,使用 r.Run
启动服务,自此,服务初始化启动完成。