over-golang/05-常用框架/gin-06-源码分析-流程梳理.md
2021-07-02 18:11:59 +08:00

5.3 KiB
Raw Permalink Blame History

一 请求流程梳理

首先从gin最开始的创建engine对象部分开始

router := gin.Default()

该方法返回了Engine结构体常见属性有

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
    // 对象池 用来创建上下文context
    pool             sync.Pool
    //记录路由方法的 比如GET POST 都会是数组中的一个 每个方法对应一个基数树的一个root的node
    trees            methodTrees
}

Default方法其实就是创建了该对象并添加了一些默认中间件

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

注意这里Default方法内部调用了New方法该方法默认添加了路由组"/"

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
}

context对象存储了上下文信息包括engine指针、request对象responsewriter对象等context在请求一开始就被创建且贯穿整个执行过程包括中间件、路由等等

type Context struct {
    writermem responseWriter
    Request   *http.Request
    Writer    ResponseWriter

    Params   Params
    handlers HandlersChain
    index    int8

    engine *Engine

    // Keys is a key/value pair exclusively for the context of each request.
    Keys map[string]interface{}

    // Errors is a list of errors attached to all the handlers/middlewares who used this context.
    Errors errorMsgs

    // Accepted defines a list of manually accepted formats for content negotiation.
    Accepted []string
}

接下来是Use方法

func (engine *Engine) Use(middleware ...HandlerFunc) IRoutes {
    //调用routegroup的use方法
    engine.RouterGroup.Use(middleware...)
    engine.rebuild404Handlers()
    engine.rebuild405Handlers()
    return engine
}

func (group *RouterGroup) Use(middleware ...HandlerFunc) IRoutes {
    //为group的handlers添加中间件 
    group.Handlers = append(group.Handlers, middleware...)
    return group.returnObj()
}

最后到达最终路由有GET,POST等多种方法但是每个方法的处理方式都是相同的即把group和传入的handler合并计算出路径存入tree中等待客户端调用

func (group *RouterGroup) GET(relativePath string, handlers ...HandlerFunc) IRoutes {
    //调用get方法
    return group.handle("GET", relativePath, handlers)
}

func (group *RouterGroup) handle(httpMethod, relativePath string, handlers HandlersChain) IRoutes {
    //计算路径地址比如group地址是 router.Group("/api")
    //结果为/api/test/ 就是最终计算出来的结果 使用path.join 方法拼接 其中加了一些判断
    absolutePath := group.calculateAbsolutePath(relativePath)
    //把group中的handler和传入的handler合并 
    handlers = group.combineHandlers(handlers)
    //把方法 路径 和处理方法作为node 加入到基数树种,基数树在下次单独学习分析
    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
}

run方法则是启动服务在http包中会有一个for逻辑不停的监听端口

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
}

func ListenAndServe(addr string, handler Handler) error {
    server := &Server{Addr: addr, Handler: handler}
    return server.ListenAndServe()
}

二 书写类似源码