分享
  1. 首页
  2. 文章

gin是怎么处理请求的,源码分析

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

一.github上gin的 quick start
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")
}

gin建立web服务的步骤:
1). 通过调用 gin.Default() 得到一个 *gin.Engine
2). 添加设置路由以及处理请求
3). 监听 8080端口

二.分析每一步是怎么处理的

1.第一步gin.Default() 中做了什么

// Default returns an Engine instance with the Logger and Recovery middleware already attached.
func Default() *Engine {
 debugPrintWARNINGDefault() //关于版本的校验等信息,debug模式下的启动日志打印
 engine := New()
 engine.Use(Logger(), Recovery())
 return engine
}

1.1 关于版本的校验等信息,debug模式下的启动日志打印
1.2 创建一个 engine

func New() *Engine {
 debugPrintWARNINGNew()
 engine := &Engine{
 RouterGroup: RouterGroup{
 Handlers: nil,
 basePath: "/",
 root: true,
 },
 FuncMap: template.FuncMap{},
 RedirectTrailingSlash: true,
 RedirectFixedPath: false,
 HandleMethodNotAllowed: false,
 ForwardedByClientIP: true,
 AppEngine: defaultAppEngine,
 UseRawPath: false,
 UnescapePathValues: true,
 MaxMultipartMemory: defaultMultipartMemory,
 trees: make(methodTrees, 0, 9),
 delims: render.Delims{Left: "{{", Right: "}}"},
 secureJsonPrefix: "while(1);",
 }
 engine.RouterGroup.engine = engine
 engine.pool.New = func() interface{} {
 return engine.allocateContext()
 }
 return engine
}

在这里我们可以看到 New 做了什么 其中engine结构体中关于处理请求最关键的有3个部分
(1)engine.pool sync.Pool类型,golang里面的连接池 返回的结构体是gin.Context结构体,便于对结构体的复用,减少gc。
(2)engine.RouterGroup (用来存储中间件 Handlers) 中间件 已经我们写的处理请求的函数 都是 HandlerFunc

// RouterGroup is used internally to configure router, a RouterGroup is associated with
// a prefix and an array of handlers (middleware).
type RouterGroup struct {
 Handlers HandlersChain
 basePath string
 engine *Engine
 root bool
}
// HandlersChain defines a HandlerFunc array.
type HandlersChain []HandlerFunc
// HandlerFunc defines the handler used by gin middleware as return value.
type HandlerFunc func(*Context)

(3)trees methodTrees 路由查找树,handler 最终存储的地方,trees中也有 HandlersChain

type methodTrees []methodTree
type methodTree struct {
 method string
 root *node
}
type node struct {
 path string
 indices string
 children []*node
 handlers HandlersChain
 priority uint32
 nType nodeType
 maxParams uint8
 wildChild bool
 fullPath string
}

1.3 加载 日志 Recovery 中间件

func (engine *Engine) Use(middleware ...HandlerFunc) IRoutes {
 engine.RouterGroup.Use(middleware...)
 engine.rebuild404Handlers()
 engine.rebuild405Handlers()
 return engine
}
// Use adds middleware to the group, see example code in GitHub.
func (group *RouterGroup) Use(middleware ...HandlerFunc) IRoutes {
 group.Handlers = append(group.Handlers, middleware...)
 return group.returnObj()
}
func (engine *Engine) rebuild404Handlers() {
 engine.allNoRoute = engine.combineHandlers(engine.noRoute)
}
func (engine *Engine) rebuild405Handlers() {
 engine.allNoMethod = engine.combineHandlers(engine.noMethod)
}

2.第二步r.GET中怎么处理的
(1)获取basePath
(2)合并之前的handlers
(3)将合并之后的handlers 存储到 trees中

r.GET("/ping", func(c *gin.Context) { })
// Group creates a new router group. You should add all the routes that have common middlewares or the same path prefix.
// For example, all the routes that use a common middleware for authorization could be grouped.
func (group *RouterGroup) Group(relativePath string, handlers ...HandlerFunc) *RouterGroup {
 return &RouterGroup{
 Handlers: group.combineHandlers(handlers),
 basePath: group.calculateAbsolutePath(relativePath),
 engine: group.engine,
 }
}
// GET is a shortcut for router.Handle("GET", path, handle).
func (group *RouterGroup) GET(relativePath string, handlers ...HandlerFunc) IRoutes {
 return group.handle("GET", relativePath, handlers)
}
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()
}
func (group *RouterGroup) combineHandlers(handlers HandlersChain) HandlersChain {
 finalSize := len(group.Handlers) + len(handlers)
 if finalSize >= int(abortIndex) {
 panic("too many handlers")
 }
 mergedHandlers := make(HandlersChain, finalSize)
 copy(mergedHandlers, group.Handlers)
 copy(mergedHandlers[len(group.Handlers):], handlers)
 return mergedHandlers
}
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) //将所有handlers 存储到 trees中
}

3.r.Run()中的处理

func (engine *Engine) Run(addr ...string) (err error) {
 defer func() { debugPrintError(err) }()
 address := resolveAddress(addr)
 debugPrint("Listening and serving HTTP on %s\n", address)
 err = http.ListenAndServe(address, engine)
 return
}
// ListenAndServe always returns a non-nil error.
func ListenAndServe(addr string, handler Handler) error {
 server := &Server{Addr: addr, Handler: handler}
 return server.ListenAndServe()
}

从这里看出gin监听流程和net/http的处理流程一致。那么engine为Server. Handler 类型的应该实现了ServeHTTP

// ServeHTTP conforms to the http.Handler interface.
func (engine *Engine) ServeHTTP(w http.ResponseWriter, req *http.Request) {
 c := engine.pool.Get().(*Context)
 c.writermem.reset(w)
 c.Request = req
 c.reset()
 engine.handleHTTPRequest(c)
 engine.pool.Put(c)
}

engine.handleHTTPRequest(c) 是请求进来 gin真正处理的地方

func (engine *Engine) handleHTTPRequest(c *Context) {
 httpMethod := c.Request.Method
 rPath := c.Request.URL.Path
 unescape := false
 if engine.UseRawPath && len(c.Request.URL.RawPath) > 0 {
 rPath = c.Request.URL.RawPath
 unescape = engine.UnescapePathValues
 }
 rPath = cleanPath(rPath)
 // Find root of the tree for the given HTTP method
 t := engine.trees
 for i, tl := 0, len(t); i < tl; i++ {
 if t[i].method != httpMethod {
 continue
 }
 root := t[i].root
 // Find route in tree
 value := root.getValue(rPath, c.Params, unescape)
 if value.handlers != nil {
 c.handlers = value.handlers
 c.Params = value.params
 c.fullPath = value.fullPath
 c.Next()
 c.writermem.WriteHeaderNow()
 return
 }
 if httpMethod != "CONNECT" && rPath != "/" {
 if value.tsr && engine.RedirectTrailingSlash {
 redirectTrailingSlash(c)
 return
 }
 if engine.RedirectFixedPath && redirectFixedPath(c, root, engine.RedirectFixedPath) {
 return
 }
 }
 break
 }
 if engine.HandleMethodNotAllowed {
 for _, tree := range engine.trees {
 if tree.method == httpMethod {
 continue
 }
 if value := tree.root.getValue(rPath, nil, unescape); value.handlers != nil {
 c.handlers = engine.allNoMethod
 serveError(c, http.StatusMethodNotAllowed, default405Body)
 return
 }
 }
 }
 c.handlers = engine.allNoRoute
 serveError(c, http.StatusNotFound, default404Body)
}

真正处理中间件跟请求的地方

// Next should be used only inside middleware.
// It executes the pending handlers in the chain inside the calling handler.
// See example in GitHub.
func (c *Context) Next() {
 c.index++
 for c.index < int8(len(c.handlers)) {
 c.handlers[c.index](c)
 c.index++
 }
}

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

本文来自:简书

感谢作者:Bomb_

查看原文:gin是怎么处理请求的,源码分析

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

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

用户登录

没有账号?注册
(追記) (追記ここまで)

今日阅读排行

    加载中
(追記) (追記ここまで)

一周阅读排行

    加载中

关注我

  • 扫码关注领全套学习资料 关注微信公众号
  • 加入 QQ 群:
    • 192706294(已满)
    • 731990104(已满)
    • 798786647(已满)
    • 729884609(已满)
    • 977810755(已满)
    • 815126783(已满)
    • 812540095(已满)
    • 1006366459(已满)
    • 692541889

  • 关注微信公众号
  • 加入微信群:liuxiaoyan-s,备注入群
  • 也欢迎加入知识星球 Go粉丝们(免费)

给该专栏投稿 写篇新文章

每篇文章有总共有 5 次投稿机会

收入到我管理的专栏 新建专栏