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

相关推荐
爱吃的小肥羊6 分钟前
刚刚!Claude最强大模型泄露,Anthropic紧急封锁
后端
qqty12177 分钟前
Spring Boot管理用户数据
java·spring boot·后端
bearpping1 小时前
SpringBoot最佳实践之 - 使用AOP记录操作日志
java·spring boot·后端
一叶飘零_sweeeet1 小时前
线上故障零扩散:全链路监控、智能告警与应急响应 SOP 完整落地指南
java·后端·spring
开心就好20252 小时前
不同阶段的 iOS 应用混淆工具怎么组合使用,源码混淆、IPA混淆
后端·ios
架构师沉默2 小时前
程序员如何避免猝死?
java·后端·架构
椰奶燕麦2 小时前
Windows PackageManager (winget) 核心故障排错与通用修复指南
后端
zjjsctcdl3 小时前
springBoot发布https服务及调用
spring boot·后端·https
zdl6864 小时前
Spring Boot文件上传
java·spring boot·后端
世界哪有真情4 小时前
哇!绝了!原来这么简单!我的 Java 项目代码终于被 “拯救” 了!
java·后端