Go小課03:Gin Simple Demo解讀

圖片

1、概述

一、簡介
  • Go官方爲了支持Web開發,提供了net/http工具包;可是在實際項目中,團隊仍是會選擇更加高效,更便捷的Web框架,如GinEcho,Beego等;
  • 在這些團隊中,不少團隊選擇了Gin這個框架,它在net/http 的基礎上作了優化;對比其餘主流框架,它更好的性能更快的路由
二、Gin的優勢
  • 快速:基於Radix樹的路由,性能很是強大。git

  • 支持中間件:內置許多中間件,如Logger,Gzip,Authorization等。github

  • 崩潰恢復:能夠捕捉panic引起的程序崩潰,使Web服務能夠一直運行。web

  • JSON驗證:能夠驗證請求中JSON數據格式。api

  • 路由分組:支持路由分組(RouteGroup),能夠更方便組織路由。數組

  • 錯誤管理機制:能夠收集程序中的錯誤bash

  • 多種數據渲染方式:支持HTMLJSONYAMLXML等數據格式的響應。服務器

  • 擴展性:很是簡單擴展中間件。數據結構

  • 數據驗證器:支持數據驗證器且能夠自定義。框架

三、Gin Simple Demo
package main

import (
	"github.com/gin-gonic/gin"
    "net/http"
)

func setupRouter() *gin.Engine {

	r := gin.Default()
	// Ping test
	r.GET("/ping", func(c *gin.Context) {
		c.JSON(http.StatusOK, gin.H{
			"status" : 0,
			"msg" 	 : "success",
			"data"   :  gin.H {
				"content" : "pong",
			},
		})
	})
	return r
}

func main() {
   r := setupRouter()
   r.Run() 
}
複製代碼

2、Gin Simple Demo 解讀

從Demo Code能夠看出,使用Gin的體驗很是順滑,定義處理Web請求就四步:導入包定義路由編寫 Handler監聽端口函數

1. 導入包
import "github.com/gin-gonic/gin"
複製代碼
2. 定義路由
  • gin.Engine是路由引擎,通常使用gin.Default()方法建立並返回gin.Engine實例.
r := gin.Default() //r默認使用了Logger和Recovery兩個中間件
複製代碼

說明:能夠用gin.New()方法建立並返回一個不包含任何中間件的gin.Engine實例

3. 編寫 Handler

經過默認路由,咱們能夠建立處理HTTP請求的方法,示例中使用GET方法:

// Ping test
r.GET("/ping", func(c *gin.Context) {
	c.JSON(http.StatusOK, gin.H{
			"status" : 0,
			"msg" 	 : "success",
			"data"   :  gin.H {
				"content" : "pong",
		},
	})
})
複製代碼
  • Get方法底層實現是調用RouterGrouphandle方法, 請求的處理是使用HandlerFunc類型方法
// 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)
}

// HandlerFunc defines the handler used by gin middleware as return value.
type HandlerFunc func(*Context) 複製代碼
  • 說明:Gin支持全部通用的HTTP請求方法,如GET,POST,PUT,PATCH,OPTIONS,HEAD,DELETE
4. 監聽端口
  • 定義好請求以後,使用Run()方法即可監聽端口,開始接受HTTP請求,若是Run()方法沒有傳入參數的話,則默認監聽8080端口。
r.Run() 
複製代碼
  • Run方法的底層實現關鍵是:http.ListenAndServe,其中:http來自net/http包。
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
}
複製代碼

3、Gin中重要數據結構

​ 在Gin Simple Demo Code中,咱們發現了三個重要的Go數據結構:gin.Enginegin.Contextgin.RouterGroup

一、gin.Engine
  • gin.Engine 是框架的入口;咱們經過 Engine 對象來定義服務路由信息、組裝插件、運行服務,整個 Web 服務的都是由它來驅動的。
// Engine is the framework's instance, it contains the muxer, middleware and configuration settings.
// Create an instance of Engine, by using New() or Default()
type Engine struct {
	RouterGroup
	
	//....
}
複製代碼
  • gin.Engine本質是對內置的 HTTP 服務器的包裝,讓它使用起來更加便捷。
  • gin.Default() 函數會生成一個默認的 Engine 對象,裏面包含了 2 個默認的經常使用插件,分別是 Logger 和 Recovery,Logger 用於輸出請求日誌,Recovery 確保單個請求發生 panic 時記錄異常堆棧日誌,輸出統一的錯誤響應(推薦使用)。
func Default() *Engine {
   debugPrintWARNINGDefault()
   engine := New()
   engine.Use(Logger(), Recovery())
   return engine
}
複製代碼
  • gin.New()函數會生成一個默認的 Engine 對象,不包含任何中間件的gin.Engine實例。
二、gin.Context
  • 請求的上下文信息對象,它是全部請求Handler的入口參數。gin.Context的結構定義以下:
// Context容許咱們在中間件之間傳遞變量,管理流程,驗證請求的JSON,並返回JSON
type Context struct {
	//請求對象
	Request   *http.Request
    
    // 用來響應 
    writermem responseWriter
	Writer    ResponseWriter
 	// URL裏面的參數,好比:/xx/:id 
	Params   Params
	
     // 參與的處理者(中間件 + 請求處理者列表)
    handlers HandlersChain
    // 當前處理到的handler的下標
    index    int8

	fullPath string
	
    // Engine單例
	engine *Engine

	// 在context能夠設置的值
	Keys map[string]interface{}

	// 一系列的錯誤
	Errors errorMsgs

	//爲內容協商定義一組手動接受的格式。
	Accepted []string

	// queryCache use url.ParseQuery cached the param query result from c.Request.URL.Query()
	queryCache url.Values

	// formCache use url.ParseQuery cached PostForm contains the parsed form data from POST, PATCH,
	// or PUT body parameters.
	formCache url.Values
}
複製代碼
  • Context這個上下文對象不是每次生成,而是從對象池裏面取出來的;而請求的真正處理核心在handleHTTPRequest函數中。
  • handleHTTPRequest函數中的核心邏輯:根據請求方法和請求的URI,找到並調用 處理的函數數組(包括咱們定義的處理函數,還有中間層的處理函數)。
func (engine *Engine) ServeHTTP(w http.ResponseWriter, req *http.Request) {

	// 從對象池中獲取一個context對象
	c := engine.pool.Get().(*Context)

	// 初始化上下文對象,由於從對象池取出來的數據,有髒數據,故要初始化。
	c.writermem.reset(w)
	c.Request = req
	c.reset()

    //處理web請求 (http請求處理)
	engine.handleHTTPRequest(c)

	//將Context對象扔回對象池了
	engine.pool.Put(c)
}
複製代碼
三、gin.RouterGroup
  • RouterGroup是路由分組,是對路由樹的包裝,全部的路由規則最終都是由它來進行管理。Engine 結構體繼承了 RouterGroup ,因此 Engine 直接具有了 RouterGroup 全部的路由管理功能。
// 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
複製代碼
  • RouteGroup 對象中主要包括:basePath(前綴路徑)、Engine 指針Handlers(處理函數數組)。

  • RouterGroup 實現了 IRouter 接口定義的一系列路由方法;這些方法最終都是經過調用 Engine.addRoute 方法將請求處理器掛接到路由樹中。

  • RouterGroup 內部有一個前綴路徑屬性,它會將全部的子路徑都加上這個前綴再放進路由樹中。有了這個前綴路徑,就能夠實現 URL 分組功能。Engine 對象內嵌的 RouterGroup 對象的前綴路徑是 /,它表示根路徑。RouterGroup 支持分組嵌套,使用 Group 方法就可讓分組下面再掛分組。

    v1 := r.Group("/api/v1")
    {
    	v1.POST("/submit",submit)
    	v1.GET("/list",list)
    }
    // Engine對象中RouterGroup對象是第一層分組(根分組),v1是根分組的子分組。
    複製代碼
四、gin.H
  • gin.H 是 map[string]interface{} 的一個快捷名稱.
type H map[string]interface{}
複製代碼
相關文章
相關標籤/搜索