跟着Gin案例学习源码-AsciiJSON

雪花还在飘落,浓雾还没散去,我仍然在行走。我在疲惫里越走越深,我想坐下来,然后就坐下了。我不知道是坐在椅子里,还是坐在石头上。我的身体摇摇晃晃坐在那里,像是超重的货船坐在波动的水面上。------《第七天》

官方案例

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 启动服务,自此,服务初始化启动完成。

相关推荐
LightOfNight6 分钟前
【后端面试题】【中间件】【NoSQL】ElasticSearch的优化方案2(减少字段、冷热分离、参数优化)
分布式·后端·elasticsearch·中间件·架构·nosql
LightOfNight1 小时前
【后端面试题】【中间件】【NoSQL】MongoDB的配置服务器、复制机制、写入语义和面试准备
分布式·后端·mongodb·中间件·面试·架构·nosql
白泽来了2 小时前
Golang 依赖注入设计哲学|12.6K 🌟 的依赖注入库 wire
开源·go
java6666688882 小时前
Spring Boot中的数据加密与解密
java·spring boot·后端
喜欢猪猪3 小时前
springboot的双亲委派
java·spring boot·后端
嗨!陌生人6 小时前
SpringSecurity中文文档(Servlet Session Management)
java·hadoop·spring boot·后端·spring cloud·servlet
randy.lou11 小时前
SpringBoot: Eureka入门
spring boot·后端·eureka
碎像11 小时前
使用AI工具 Baidu Comate 辅助编码 快速定位修改Bug
java·前端·后端·bug·intellij idea
AQin101211 小时前
【填坑向】后端如何处理CORS跨域问题
后端
404_NOT_FOUND@12 小时前
javaEE——Servlet
后端