<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ThinkChat2.0新版上線,更智能更精彩,支持會話、畫圖、視頻、閱讀、搜索等,送10W Token,即刻開啟你的AI之旅 廣告
                路由調用邏輯 gin 對外宣傳的高效,很大一部分是說其路由效率。本文內容包括: - 路由API介紹 - 路由調用實現邏輯 - 路由的內部實現 ## 路由API ### 設置路由 ``` // routergroup.go:20 type IRoutes interface { Use(handlers ...HandlerFunc) IRoutes Handle(httpMethod, relativePath string, handlers ...HandlerFunc) IRoutes Any(relativePath string, handlers ...HandlerFunc) IRoutes GET(relativePath string, handlers ...HandlerFunc) IRoutes POST(relativePath string, handlers ...HandlerFunc) IRoutes DELETE(relativePath string, handlers ...HandlerFunc) IRoutes PATCH(relativePath string, handlers ...HandlerFunc) IRoutes PUT(relativePath string, handlers ...HandlerFunc) IRoutes OPTIONS(relativePath string, handlers ...HandlerFunc) IRoutes HEAD(relativePath string, handlers ...HandlerFunc) IRoutes StaticFile(relativePath, filepath string) IRoutes Static(relativePath, root string) IRoutes StaticFS(relativePath string, fs http.FileSystem) IRoutes } // routergroup.go:15 type IRouter interface { IRoutes Group(string, ...HandlerFunc) *RouterGroup } ``` ### RouteGroup的獲取 - Engine嵌入了RouteGroup,它本身就實現了IRoutes接口,gin.New() 和 gin.Default() 可以得到Engine對象 - Engine.Group(relativePath string, handlers ...HandlerFunc)可以得到一個新的RouteGroup ### 路由的命中 初始化時將 `gin.go:handleHTTPRequest` 設置為http請求的處理者,它會將請求進行預處理后去處查找命中的處理者(列表),然后去執行。 這個是調用邏輯,我們講具體實現。 ## 路由的調用邏輯 ### 背景知識 我們先看 `Engine` 結構體和路由有關的字段 ``` gin.go:50 type Engine struct { RouterGroup // 如果true,當前路由匹配失敗但將路徑最后的 / 去掉時匹配成功時自動匹配后者 // 比如:請求是 /foo/ 但沒有命中,而存在 /foo, // 對get method請求,客戶端會被301重定向到 /foo // 對于其他method請求,客戶端會被307重定向到 /foo RedirectTrailingSlash bool // 如果true,在沒有處理者被注冊來處理當前請求時router將嘗試修復當前請求路徑 // 邏輯為: // - 移除前面的 ../ 或者 // // - 對新的路徑進行大小寫不敏感的查詢 // 如果找到了處理者,請求會被301或307重定向 // 比如: /FOO 和 /..//FOO 會被重定向到 /foo // RedirectTrailingSlash 參數和這個參數獨立 RedirectFixedPath bool // 如果true,當路由沒有被命中時,去檢查是否有其他method命中 // 如果命中,響應405 (Method Not Allowed) // 如果沒有命中,請求將由 NotFound handler 來處理 HandleMethodNotAllowed bool // 如果true, url.RawPath 會被用來查找參數 UseRawPath bool // 如果true, path value 會被保留 // 如果 UseRawPath是false(默認),UnescapePathValues為true // url.Path會被保留并使用 UnescapePathValues bool allNoRoute HandlersChain allNoMethod HandlersChain noRoute HandlersChain noMethod HandlersChain //每個http method對應一棵樹 trees methodTrees } // gin.go:30 type HandlerFunc func(*Context) type HandlersChain []HandlerFunc // routergroup.go:40 type RouterGroup struct { // 這個路由會參與處理的函數列表 Handlers HandlersChain basePath string // 單例存在 engine *Engine // 是否是根 root bool } ``` ### 添加路由 ``` // routergroup.go:70 func (group *RouterGroup) handle(httpMethod, relativePath string, handlers HandlersChain) IRoutes { // 將basePath和relativePath加起來得到最終的路徑 absolutePath := group.calculateAbsolutePath(relativePath) // 將現有的 Handlers 和 handlers合并起來 handlers = group.combineHandlers(handlers) // 將這個route加入到engine.tree group.engine.addRoute(httpMethod, absolutePath, handlers) // 返回 return group.returnObj() } ``` 上面的 `addRoute()` 的實現: ``` 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) // 維護engine.trees root := engine.trees.get(method) if root == nil { root = new(node) engine.trees = append(engine.trees, methodTree{method: method, root: root}) } // 核心,后面一起來講 root.addRoute(path, handlers) } ``` ### 查找路由 我們看看路由查找邏輯: ``` gin.go:340 func (engine *Engine) handleHTTPRequest(c *Context) { httpMethod := c.Request.Method path := c.Request.URL.Path unescape := false // 看是否使用 RawPath if engine.UseRawPath && len(c.Request.URL.RawPath) > 0 { path = c.Request.URL.RawPath unescape = engine.UnescapePathValues } t := engine.trees // 根據 http method 得到目標樹 for i, tl := 0, len(t); i < tl; i++ { if t[i].method == httpMethod { // 目標樹找到了,為本次請求路由樹的根節點 root := t[i].root // 根據path查找節點 // 核心,后面來講 handlers, params, tsr := root.getValue(path, c.Params, unescape) if handlers != nil { c.handlers = handlers c.Params = params c.Next() c.writermem.WriteHeaderNow() return } if httpMethod != "CONNECT" && path != "/" { // 如果 trailing slash redirect,就重定向出去 if tsr && engine.RedirectTrailingSlash { redirectTrailingSlash(c) return } // fix path if engine.RedirectFixedPath && redirectFixedPath(c, root, engine.RedirectFixedPath) { return } } // 沒找到 break } } // 如果是因為HTTP method有誤,回復這個 if engine.HandleMethodNotAllowed { for _, tree := range engine.trees { if tree.method != httpMethod { if handlers, _, _ := tree.root.getValue(path, nil, unescape); handlers != nil { c.handlers = engine.allNoMethod serveError(c, 405, default405Body) return } } } } // 交給 NotRoute (404) c.handlers = engine.allNoRoute serveError(c, 404, default404Body) } ```
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看