Golang之Gin框架源码解读——第一章

本文介绍了Gin框架如何组织和映射URL到处理函数,探讨了RouterGroup、路由根树的数据结构,并揭示了Gin处理路由信息的内部机制。在分析源码过程中,发现了Gin在特定路由规则下可能出现的问题,提醒开发者注意避免此类问题。
摘要由CSDN通过智能技术生成

Gin是使用Go语言编写的高性能的web服务框架,根据官方的测试,性能是httprouter的40倍左右。要使用好这套框架呢,首先我们就得对这个框架的基本结构有所了解,所以我将从以下几个方面来对Gin的源码进行解读。

  • 第一章:Gin是如何储存和映射URL路径到相应的处理函数的
  • 第二章:Gin中间件的设计思想及其实现
  • 第三章:Gin是如何解析客户端发送请求中的参数的
  • 第四章:Gin是如何将各类格式(JSON/XML/YAML等)数据解析返回的

Gin Github官方地址

Gin是如何组织和映射URL到处理函数的

在谈这个之前我们先以官方给的示例代码来作为我们的切入口,然后一步一步的看Gin是如何处理的,了解Gin的深层次工作原理。

func main() {
   
	router := gin.Default()

	// 这个处理函数将会匹配 /user/john 但不会匹配 /user/ 或者 /user
	router.GET("/user/:name", func(c *gin.Context) {
   
		name := c.Param("name")
		c.String(http.StatusOK, "Hello %s", name)
	})

	// 这个路径将会匹配 /user/john/ 或者 /user/john/send
	// 如果没有匹配到 /user/john, 那么将会被重定向到 /user/john/
	router.GET("/user/:name/*action", func(c *gin.Context) {
   
		name := c.Param("name")
		action := c.Param("action")
		message := name + " is " + action
		c.String(http.StatusOK, message)
	})

	router.POST("/user/:name/*action", func(c *gin.Context) {
   
		log.Println(c.FullPath() == "/user/:name/*action") // true
	})

	router.Run(":8080")
}

首先,我们要通过gin.Default()获取到一个Engine对象指针,然后由router来负责将各个映射路径记录到处理的映射关系。我们先来看下Engine的数据结构是怎样的。

type Engine struct {
   
    //中间件信息就存储在这个里面
	RouterGroup
    //是否启动自动重定向。例如:配置Handler时是/foo,
    //但实际发送的请求是/foo/。在启用本选项后,将会重定向到/foo
	RedirectTrailingSlash bool

    // 是否启动请求路由修复功能。
    // 启用过后,当/../foo找不到匹配路由时,会自动删除..部分路由,然后重新匹配知道找到匹配路由,如上路由就会被匹配到/foo
	RedirectFixedPath bool

    //启用后,如果找不到当前路由匹配的HTTP方法,
    //而在其他HTTP方法中能找到,则返回405响应码。
    HandleMethodNotAllowed bool
    //是否获取真正的客户端IP,而不是代理服务器IP(nginx等),
    // 开启后将会从"X-Real-IP和X-Forwarded-For"中解析得到客户端IP
	ForwardedByClientIP    bool

	//启用后将在头部加入"X-AppEngine"标识,以便与PaaS集成
	AppEngine bool

    //启用后,将使用原有的URL.rawPath(没有对转义字符进行处理的,
    // 如%/+等)地址来进行解析,而不是使用URL.path来解析,默认为false
	UseRawPath bool

	//如果启用,则路径中的转义字符将不会被转义
	UnescapePathValues bool

	//设置用来缓存客户端发送的文件的缓冲区大小,默认:32MB
	MaxMultipartMemory int64

	//启用后将会删除多余的分隔符"/"
	RemoveExtraSlash bool

    //用于保存tmpl文件中用于引用变量的定界符,默认是"{
   {}}",
    // 调用r.Delims("{[{", "}]}")可以修改
    delims           render.Delims
    //设置防止JSON劫持,在json字符串前加的逻辑代码,
    //默认是:"while(1);"
    secureJsonPrefix string
    //html文件解析器
    HTMLRender       render.HTMLRender
    //tmpl文件的内建函数列表,可以在tmpl文件中调用函数,使用
    //router.SetFuncMap(template.FuncMap{
   
    //      "formatAsDate": formatAsDate,
    //})可设置
    FuncMap          template.FuncMap
    // HandlersChain就是func(*Context)数组
    // 以下四个调用链中保存的就是在不同情况下回调的处理函数
    // 找不到匹配路由(404)
    allNoRoute       HandlersChain
    //返回405状态时会回调
    allNoMethod      HandlersChain
    //没有配置路由时回调,主要是代码测试时候使用的
    noRoute          HandlersChain
    //没有配置映射方法时回调,主要是代码测试时候使用的
    noMethod         HandlersChain
    //连接池用于保存与客户端的连接上下文(Context)
    pool             sync.Pool
    //路径搜索树,代码中配置的路由信息都以树节点的形式组织起来
    // 下面会详细介绍
	trees            methodTrees
}

在大致了解完Gin的核心对象Engine之后,我们脑海里就可以有一个大致的结构了。因为整个框架都是为绕着Engine来进行编写的,下面我们就重点介绍一下Engine中的几个比较重要的结构,来更深入地了解Gin

RouterGroup

type RouterGroup struct {
   
	Handlers HandlersChain
    basePath string
    //注意这里存在交叉依赖
	engine   *Engine
	root     bool
}

光看这个RouterGroup结构体,我们仿佛还不太清楚他的作用是什么,不过我们通过一下几个方法就可以知道了。

func (group *RouterGroup) Use(middleware ...HandlerFunc) IRoutes {
   
	group.Handlers = append(group.Handlers, middleware...)
	return group.returnObj()
}

从这里函数一看,咦?这不就是绑定中间件方法吗?从这里我们就可以看出RouterGroupHandlers是用于储存中间件函数的。除此之外,RouterGroup还实现了IRoutes接口。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值