zoukankan      html  css  js  c++  java
  • go web framework gin 启动流程分析

    最主要的package : gin

    最主要的struct: Engine

    Engine 是整个framework的实例,它包含了muxer, middleware, configuration settings. 通过New() 或者Default()来创建一个Engine 的实例。

    type Engine struct {
        RouterGroup
    
        // Enables automatic redirection if the current route can't be matched but a
        // handler for the path with (without) the trailing slash exists.
        // For example if /foo/ is requested but a route only exists for /foo, the
        // client is redirected to /foo with http status code 301 for GET requests
        // and 307 for all other request methods.
        RedirectTrailingSlash bool
    
        // If enabled, the router tries to fix the current request path, if no
        // handle is registered for it.
        // First superfluous path elements like ../ or // are removed.
        // Afterwards the router does a case-insensitive lookup of the cleaned path.
        // If a handle can be found for this route, the router makes a redirection
        // to the corrected path with status code 301 for GET requests and 307 for
        // all other request methods.
        // For example /FOO and /..//Foo could be redirected to /foo.
        // RedirectTrailingSlash is independent of this option.
        RedirectFixedPath bool
    
        // If enabled, the router checks if another method is allowed for the
        // current route, if the current request can not be routed.
        // If this is the case, the request is answered with 'Method Not Allowed'
        // and HTTP status code 405.
        // If no other Method is allowed, the request is delegated to the NotFound
        // handler.
        HandleMethodNotAllowed bool
        ForwardedByClientIP    bool
    
        // #726 #755 If enabled, it will thrust some headers starting with
        // 'X-AppEngine...' for better integration with that PaaS.
        AppEngine bool
    
        // If enabled, the url.RawPath will be used to find parameters.
        UseRawPath bool
    
        // If true, the path value will be unescaped.
        // If UseRawPath is false (by default), the UnescapePathValues effectively is true,
        // as url.Path gonna be used, which is already unescaped.
        UnescapePathValues bool
    
        // Value of 'maxMemory' param that is given to http.Request's ParseMultipartForm
        // method call.
        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
    }

    获取一个gin Engin的实例:r := gin.Default()

    查看gin.Default()方法的实现:

    // Default returns an Engine instance with the Logger and Recovery middleware already attached.
    func Default() *Engine {
    	debugPrintWARNINGDefault()
    	engine := New()  #实例化一个engine
    	engine.Use(Logger(), Recovery())
    	return engine
    }
    

      查看New()的实现:

    // New returns a new blank Engine instance without any middleware attached.
    // By default the configuration is:
    // - RedirectTrailingSlash:  true
    // - RedirectFixedPath:      false
    // - HandleMethodNotAllowed: false
    // - ForwardedByClientIP:    true
    // - UseRawPath:             false
    // - UnescapePathValues:     true
    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{} { //这里定义了engine.pool.New方法,所以在Get()的时候,如果为nil,那么直接执行New 方法
    		return engine.allocateContext()
    	}
    	return engine
    }
    

     如果engine.pool.New被执行,那么将返回一个*Context类型的指针。

    func (engine *Engine) allocateContext() *Context {
    	return &Context{engine: engine}
    }

    然后调用r.Run(":8080"), 在本地网卡上监听8080端口,等待连接。实际上调用的是:http.ListenAndServe(address, engine)

    查看http.ListenAndServe方法:

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

     它且将addr 和handler作为参数实例化了一个Server, 然后调用server.ListenAndServe()方法等待连接。

    查看Handler的定义:

    type Handler interface {
    	ServeHTTP(ResponseWriter, *Request)
    }
    

     它是一个interface, 那么也就是说它作为参数的话,那么这个struct必须实现ServeHTTP(ResponseWriter, *Request) 这个方法。

    在gin.go中查看ServeHTTP方法的定义:

    // ServeHTTP conforms to the http.Handler interface.
    func (engine *Engine) ServeHTTP(w http.ResponseWriter, req *http.Request) {
    	c := engine.pool.Get().(*Context) 返回的是New()里面定义的func,然后执行。
    	c.writermem.reset(w)
    	c.Request = req
    	c.reset()
    
    	engine.handleHTTPRequest(c)
    
    	engine.pool.Put(c)
    }
    

     这里的engine.pool.Get().(*Context) 方法,实际上执行的是上面的New方法,所以得到的是一个Context类型的指针。

    分析到这里,也就是说,如果有一个HTTP请求到来,那么会先触发ServeHTTP方法得到一个Context请求上下文,然后调用engine.handleHTTPRequest(C),处理这个请求,同时将处理的内容写入到http.ResponseWriter中。

    关于engine.handleHTTPRequest()如何实现的,参考gin 路由表的设计

    处理完以后为什么还要执行engine.pool.Put(c)呢?

    因为:engine.pool需要一个buffer来存储内容,当下一个请求到达的时候,就可以直接来使用,避免又调用一次New函数,节省了内存。

  • 相关阅读:
    网盘无法单独同步某个文件的解决方法
    编译cubieboard android 源码过程详解之(七):lichee build
    cb-A10系统优化之(一):去除自启动软件
    ubuntu 使用
    JS——数组中push对象,覆盖问题,每次都创建一个新的对象
    Node.js中npm常用命令大全
    Vue style里面使用@import引入外部css, 作用域是全局的解决方案
    5大浏览器内核和主要代表
    IE调试网页之三:使用 F12 工具控制台查看错误和状态 (Windows)
    div拖拽到iframe上方 导致 缩放和拖拽的不平滑和鼠标事件未放开 解决方法
  • 原文地址:https://www.cnblogs.com/Spider-spiders/p/10221804.html
Copyright © 2011-2022 走看看