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

相关推荐
计算机毕设VX:Fegn08955 小时前
计算机毕业设计|基于springboot + vue蛋糕店管理系统(源码+数据库+文档)
数据库·vue.js·spring boot·后端·课程设计
没差c6 小时前
springboot集成flyway
java·spring boot·后端
三水不滴6 小时前
Redis 过期删除与内存淘汰机制
数据库·经验分享·redis·笔记·后端·缓存
笨蛋不要掉眼泪6 小时前
Spring Boot集成LangChain4j:与大模型对话的极速入门
java·人工智能·后端·spring·langchain
sheji34169 小时前
【开题答辩全过程】以 基于SpringBoot的疗养院管理系统的设计与实现为例,包含答辩的问题和答案
java·spring boot·后端
短剑重铸之日9 小时前
《设计模式》第六篇:装饰器模式
java·后端·设计模式·装饰器模式
码界奇点11 小时前
基于Flask与OpenSSL的自签证书管理系统设计与实现
后端·python·flask·毕业设计·飞书·源代码管理
代码匠心12 小时前
从零开始学Flink:状态管理与容错机制
java·大数据·后端·flink·大数据处理
分享牛12 小时前
LangChain4j从入门到精通-11-结构化输出
后端·python·flask
Grassto12 小时前
11 Go Module 缓存机制详解
开发语言·缓存·golang·go·go module