简介

Gin is a web framework written in Go (Golang). It features a martini-like API with performance that is up to 40 times faster thanks to [httprouter](https://github.com/julienschmidt/httprouter). If you need performance and good productivity, you will love Gin.

  • 项目地址[https://github.com/gin-gonic/gin](https://github.com/gin-gonic/gin) ```go package main

import “github.com/gin-gonic/gin”

func main() { r := gin.Default() r.GET(“/ping”, func(c *gin.Context) { c.JSON(200, gin.H{ “message”: “pong”, }) }) r.Run() // listen and serve on 0.0.0.0:8080 (for windows “localhost:8080”) }

  1. <a name="MlbXu"></a>
  2. ## Engine
  3. - Engine是给用户使用的具体实例
  4. - 提供了muxer、middleware、configuration settings功能
  5. - 注意Engine复用了RouterGroup,因此它也是一个根路由,具有路由组的相关功能
  6. ```go
  7. type Engine struct {
  8. //实现路由功能, Engine即是根路由
  9. RouterGroup
  10. delims render.Delims
  11. HTMLRender render.HTMLRender
  12. FuncMap template.FuncMap
  13. allNoRoute HandlersChain
  14. allNoMethod HandlersChain
  15. noRoute HandlersChain
  16. noMethod HandlersChain
  17. //pool是gin实现的对象池,针对Context等频繁创建的对象提供缓存功能
  18. pool sync.Pool
  19. //由url和调用链构成的radix tree, 用于路由请求
  20. trees methodTrees
  21. maxParams uint16
  22. maxSections uint16
  23. trustedProxies []string
  24. trustedCIDRs []*net.IPNet
  25. }
  • Engine有两个初始化方法
    • New提供基本的Engine,不附带任何middleware
    • Default基于基本的Engine,提供log和recover功能的middleware ```go func New() *Engine { engine := &Engine{ RouterGroup: RouterGroup{
      1. Handlers: nil,
      2. basePath: "/",
      3. root: true,
      }, //… } engine.RouterGroup.engine = engine engine.pool.New = func() interface{} { return engine.allocateContext() } return engine }

func Default() *Engine { debugPrintWARNINGDefault() engine := New() engine.Use(Logger(), Recovery()) return engine }

  1. - 核心方法
  2. - Run启动函数,开始监听并处理请求
  3. ```go
  4. func (engine *Engine) Run(addr ...string) (err error) {
  5. address := resolveAddress(addr)
  6. debugPrint("Listening and serving HTTP on %s\n", address)
  7. //可以看到网络层主要是复用go的http库,engine本身实现了ServeHttp()
  8. err = http.ListenAndServe(address, engine)
  9. return
  10. }
  11. // ServeHTTP conforms to the http.Handler interface.
  12. func (engine *Engine) ServeHTTP(w http.ResponseWriter, req *http.Request) {
  13. //从对象池取一个Context
  14. c := engine.pool.Get().(*Context)
  15. c.writermem.reset(w)
  16. c.Request = req
  17. //对象重置
  18. c.reset()
  19. engine.handleHTTPRequest(c)
  20. //归还对象
  21. engine.pool.Put(c)
  22. }
  23. //handleHTTPRequest 根据请求执行对应的处理流程
  24. func (engine *Engine) handleHTTPRequest(c *Context) {
  25. httpMethod := c.Request.Method
  26. //1. 根据requestMethod找到对应的radix tree
  27. t := engine.trees
  28. for i, tl := 0, len(t); i < tl; i++ {
  29. if t[i].method != httpMethod {
  30. continue
  31. }
  32. root := t[i].root
  33. //2. 根据url在radix tree中找到对应的节点数据
  34. value := root.getValue(rPath, c.params, c.skippedNodes, unescape)
  35. if value.params != nil {
  36. c.Params = *value.params
  37. }
  38. if value.handlers != nil {
  39. //3. 为Context设置handlers调用链
  40. c.handlers = value.handlers
  41. c.fullPath = value.fullPath
  42. //4. 开始执行调用链
  43. c.Next()
  44. c.writermem.WriteHeaderNow()
  45. return
  46. }
  47. break
  48. }
  49. //5. 针对找不到handler的请求进行处理
  50. if engine.HandleMethodNotAllowed {
  51. for _, tree := range engine.trees {
  52. if tree.method == httpMethod {
  53. continue
  54. }
  55. if value := tree.root.getValue(rPath, nil, c.skippedNodes, unescape); value.handlers != nil {
  56. c.handlers = engine.allNoMethod
  57. serveError(c, http.StatusMethodNotAllowed, default405Body)
  58. return
  59. }
  60. }
  61. }
  62. c.handlers = engine.allNoRoute
  63. serveError(c, http.StatusNotFound, default404Body)
  64. }
  65. func (c *Context) Next() {
  66. c.index++
  67. for c.index < int8(len(c.handlers)) {
  68. c.handlers[c.index](c)
  69. c.index++
  70. }
  71. }
  • addRoute注册请求处理方法,通过RouterGroup进行注册的方法最终都会调用Engine.addRoute,将对应的url和调用链添加到Engine的radix tree中。所以Gin中请求处理方法都是维护在Engine上的,而不是在RouterGroup,RouterGroup更多的是提供给用户向使用的东西

    1. func (n *node) addRoute(path string, handlers HandlersChain) {
    2. fullPath := path
    3. n.priority++
    4. //1. 空树, 将节点添加到父节点的子节点中
    5. if len(n.path) == 0 && len(n.children) == 0 {
    6. n.insertChild(path, fullPath, handlers)
    7. n.nType = root
    8. return
    9. }
    10. //2. 查找最长公共前缀, 并插入节点
    11. walk:
    12. for {
    13. i := longestCommonPrefix(path, n.path)
    14. //2.1 当前节点和待插入节点存在部分公共前缀,需要分裂当前节点(公共部分、非公共部分)
    15. if i < len(n.path) {
    16. //2.1.1 分裂非公共部分,并继承当前节点的子节点们
    17. child := node{
    18. path: n.path[i:],
    19. wildChild: n.wildChild,
    20. indices: n.indices,
    21. children: n.children,
    22. handlers: n.handlers,
    23. priority: n.priority - 1,
    24. fullPath: n.fullPath,
    25. }
    26. //2.1.2 修改当前节点的path,并把分裂出来的节点作为当前节点的子节点
    27. n.children = []*node{&child} n.indices = bytesconv.BytesToString([]byte{n.path[i]})
    28. n.path = path[:i]
    29. n.handlers = nil
    30. n.wildChild = false
    31. n.fullPath = fullPath[:parentFullPathIndex+i]
    32. }
    33. //2.2 待插入节点和当前节点存在部分公共前缀,需要确定待插入节点和当前节点的子节点
    34. //是否存在公共前缀, 若存在则取对应子节点继续执行walk过程; 否则直接将待插入节点
    35. //插入到当前节点的子节点中
    36. if i < len(path) {
    37. path = path[i:] //取待插入节点的非公共部分
    38. c := path[0]
    39. //2.2.1 检查是否和子节点存在公共前缀(首字母), 存在则取该子节点, 继续walk
    40. for i, max := 0, len(n.indices); i < max; i++ {
    41. if c == n.indices[i] {
    42. parentFullPathIndex += len(n.path)
    43. i = n.incrementChildPrio(i)
    44. n = n.children[i]
    45. continue walk
    46. }
    47. }
    48. //2.2.2 和子节点不存在公共部分, 直接插入到子节点中
    49. if c != ':' && c != '*' && n.nType != catchAll {
    50. //通配符检查
    51. } else if n.wildChild {
    52. //通配符检查
    53. }
    54. n.insertChild(path, fullPath, handlers)
    55. return
    56. }
    57. //2.3 待插入节点和当前节点路径完全一致, 将handlers存到当前当前节点
    58. if n.handlers != nil {
    59. panic("handlers are already registered for path '" + fullPath + "'")
    60. }
    61. n.handlers = handlers
    62. n.fullPath = fullPath
    63. return
    64. }
    65. }

RouterGroup

  • 用于配置请求的公共路由 ```go type RouterGroup struct { Handlers HandlersChain //中间件调用链 basePath string //公共路径 engine *Engine //egine引用 root bool }

//RouterGroup实现了IRouter接口, 提供如下方法 // IRouter defines all router handle interface includes single and group router. type IRouter interface { IRoutes Group(string, …HandlerFunc) *RouterGroup }

// IRoutes defines all router handle interface. type IRoutes interface { Use(…HandlerFunc) IRoutes

  1. Handle(string, string, ...HandlerFunc) IRoutes
  2. Any(string, ...HandlerFunc) IRoutes
  3. GET(string, ...HandlerFunc) IRoutes
  4. POST(string, ...HandlerFunc) IRoutes
  5. DELETE(string, ...HandlerFunc) IRoutes
  6. PATCH(string, ...HandlerFunc) IRoutes
  7. PUT(string, ...HandlerFunc) IRoutes
  8. OPTIONS(string, ...HandlerFunc) IRoutes
  9. HEAD(string, ...HandlerFunc) IRoutes
  10. StaticFile(string, string) IRoutes
  11. Static(string, string) IRoutes
  12. StaticFS(string, http.FileSystem) IRoutes

}

  1. - 核心方法
  2. - Group基于当前RouterGroup再创建出一个新的RouterGroup
  3. ```go
  4. // Group creates a new router group. You should add all the routes that have common middlewares or the same path prefix.
  5. // For example, all the routes that use a common middleware for authorization could be grouped.
  6. func (group *RouterGroup) Group(relativePath string, handlers ...HandlerFunc) *RouterGroup {
  7. return &RouterGroup{
  8. Handlers: group.combineHandlers(handlers),
  9. basePath: group.calculateAbsolutePath(relativePath),
  10. engine: group.engine,
  11. }
  12. }
  • Use给RouterGroup安装新的middlewares

    1. // Use adds middleware to the group, see example code in GitHub.
    2. func (group *RouterGroup) Use(middleware ...HandlerFunc) IRoutes {
    3. group.Handlers = append(group.Handlers, middleware...)
    4. return group.returnObj()
    5. }
  • handle所有方法注册最终都会调用该方法进行注册,内部最终调用Engine.addRoute添加路由

    1. func (group *RouterGroup) handle(httpMethod, relativePath string, handlers HandlersChain) IRoutes {
    2. absolutePath := group.calculateAbsolutePath(relativePath)
    3. handlers = group.combineHandlers(handlers)
    4. group.engine.addRoute(httpMethod, absolutePath, handlers)
    5. return group.returnObj()
    6. }

Context

  • Context是Gin框架自定义的,用于在调用链中传递请求参数和渲染响应数据等

    1. type Context struct {
    2. writermem responseWriter
    3. Request *http.Request
    4. Writer ResponseWriter
    5. Params Params
    6. handlers HandlersChain
    7. index int8
    8. fullPath string
    9. engine *Engine
    10. params *Params
    11. skippedNodes *[]skippedNode
    12. // This mutex protect Keys map
    13. mu sync.RWMutex
    14. // Keys is a key/value pair exclusively for the context of each request.
    15. Keys map[string]interface{}
    16. // Errors is a list of errors attached to all the handlers/middlewares who used this context.
    17. Errors errorMsgs
    18. // Accepted defines a list of manually accepted formats for content negotiation.
    19. Accepted []string
    20. // queryCache use url.ParseQuery cached the param query result from c.Request.URL.Query()
    21. queryCache url.Values
    22. // formCache use url.ParseQuery cached PostForm contains the parsed form data from POST, PATCH,
    23. // or PUT body parameters.
    24. formCache url.Values
    25. // SameSite allows a server to define a cookie attribute making it impossible for
    26. // the browser to send this cookie along with cross-site requests.
    27. sameSite http.SameSite
    28. }