gin 总结

Mandelbrot_Kobe · · 2705 次点击 · · 开始浏览    
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

gin框架概述

  • 前面写了两篇从源代码层面审视gin框架的文章,写完之后感觉结构比较乱。这里再重新总结一下
  • 作为web框架,gin相对beego等更加轻量化,没有orm等内容,gin实现了路由封装,日志,鉴权等功能。核心部分,是实现RESTful规范。将http method对应的path,找到相应的handler去处理请求,最终响应http请求。

gin框架的设计思路

  • golang语言的一个重要特点就是拥有高质量的官方标准库。设计web框架,自然也是离不开net/http包。下面是一个简单的http server实现。

    clipboard.png

  • 上边这个例子,定义了一个struct,这个struct实现了http包的Handler接口,即ServeHTTP方法,那么,就可以把这个struct当成Handler传给ListenAndServe。
  • 其实,gin框架也是这个思路,定义了名为Engine的struct,然后实现这个Engine实现了ServeHTTP方法,然后再将这个Engine作为Handler传给ListenAndServe就行。然后中间所有的路由管理,path对应的handler等,都由ServeHTTP去调用相应的实现函数。

启动Engine

  • Engine作为核心的Handler,在gin框架中属于核心位置,这里贴出Engine的完整定义,重要字段的含义会在下文详细阐述。这个定义非常明显的特点就是定义了很多的bool类型的变量,很容易猜到这些bool值其实就是处理的flow的“路牌”
type Engine struct {
    RouterGroup
    RedirectTrailingSlash bool
    RedirectFixedPath bool
    HandleMethodNotAllowed bool
    ForwardedByClientIP    bool
    AppEngine bool
    UseRawPath bool
    UnescapePathValues bool
    MaxMultipartMemory int64
    delims           render.Delims
    secureJsonPrefix string
    HTMLRender       render.HTMLRender
    FuncMap          template.FuncMap
    allNoRoute       HandlersChain
    allNoMethod      HandlersChain
    noRoute          HandlersChain
    noMethod         HandlersChain
    pool             sync.Pool
    trees            methodTrees
}
  • 如何启动Engine呢?有了上面的例子,具体如何启动其实并不意外。

    clipboard.png

  • 启动之后,http请求自然就会交给Engine的ServeHTTP来处理。但是,我们还不能马上揭开ServeHTTP的面纱,我们需要先了解gin是如何组织和管理http method, path和handler的。

gin管理method,path和handler

怎么用gin

  • 在弄清楚gin如何管理method,path和handler之前,先看看,gin一般都是怎么用的。gin 例子。如果没有gin的使用经验,往下阅读之前,务必浏览这个例子。
  • gin.Default会生成一个Engine对象,再由这个对象去注册相关的路由组,路由,method和handler。

路由管理——RouteGroup

  • 上边Engine结构第一个变量就是继承了RouteGroup。之所以不定义新的变量,比如 rg RouteGroup来使用RouteGroup,是因为Engine需要直接使用RouteGroup实现的IRouter接口。

    type RouterGroup struct {
       Handlers HandlersChain
       basePath string
       engine   *Engine
       root     bool
    }

    clipboard.png

  • IRouter的Group函数的实现就是用作路由组管理。只要将正确的参数(string,HandlerFunc)传给GET,POST等方法,就可以将string对应的path,交给HandlerFunc来处理。(后边会解释HandlerFunc)

Handler是怎么设计的

  • 上边的方法,HandlerFunc是重要的角色。那HandlerFunc是什么呢?

    clipboard.png

  • HandlerFunc是函数类型,函数的参数是Context对象。上边链接里的例子也可以看出来,在使用gin框架时,业务逻辑的处理主要就是在自己定义的HandlerFunc里边。入参是*Context。这个Context又是啥?

    clipboard.png

  • 从Context的代码注释,就可以看出Context结构在gin框架中的重要性了。请求包含的数据,响应需要的数据,在Context里边都涵盖了。
  • 对比原生的http包,一个是需要实现ServeHTTP方法,一个是需要实现HandlerFunc函数。(method和function在编程里边是有区别的,千万不要混为一谈)

管理http method

  • 当用户发起POST请求之后,是怎么找到注册的对应的POST方法的HandlerFunc的呢?这就要看IRouter接口的POST方法被调用的时候发生了什么。

    clipboard.png
    clipboard.png

  • 上边的源码可以看出来,在整理path和handlers之后,会让engine进行addRoute操作。

    clipboard.png

  • 用树结构存储path,是一个非常自然的思路。除此之外,gin框架还生成了好几棵树,每棵树对应一个http method。POST请求的话就回去POST树上边找对应的path和HandlerFunc。这个树有专业名词:基数树!

总结

  • gin框架会生成几棵基数树,分别对应http method。树结构对应path的树状形态,每个path会map到一个HandlerFunc。这样,在接收到http请求的时候,先找到该请求对应的http method树,再根据URL的path找到注册好的HandlerFunc。HandlerFunc对应的业务逻辑需要gin的使用者借助Context结构自行处理。

Engine的ServeHTTP

  • 有了gin管理http method,path和HandlerFunc的基础之后,我们将目光转回Engine的ServeHTTP方法当中来。

    clipboard.png

  • 虽然上边的代码不难理解,但是这段代码对gin的性能影响至关重要。关键的部分在于借助sync.Pool对Context进行复用。
  • 核心的处理逻辑最后交给handleHTTPRequest了。核心逻辑由源代码翻译过来就是:在接收到http请求的时候,先找到该请求对应的http method树,再根据URL的path找到注册好的HandlerFunc。HandlerFunc对应的业务逻辑需要gin的使用者借助Context结构自行处理。

有疑问加站长微信联系(非本文作者)

本文来自:Segmentfault

感谢作者:Mandelbrot_Kobe

查看原文:gin 总结

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

2705 次点击  
加入收藏 微博
1 回复  |  直到 2021-05-07 23:20:34
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传