Go語言的Gin框架快速入門篇


             Go語言的Gin框架快速入門篇

                                        作者:尹正傑

版權聲明:原創作品,謝絕轉載!否則將追究法律責任。

 

 

一.Gin框架概述

1>.Go語言的Web框架概述

  框架就是別人寫好的代碼我們可以直接使用,這個代碼是專門針對一個開發方向定制的。例如,我們要做一個網站,利用框架就能非常塊的完成網站的開發,如果沒有框架,每個細節都需要我們處理,開發時間會大大降低。

  Go語言常見的web框架有beego,gin,echo,iris等等。值得一提的是,beego框架是咱們國人謝孟軍開發的,其地位和Python的Django有點類似,而gin框架的地位和python的flask有點類似。

  綜上所述,如果你要做純web開發推薦大家使用beego,如果你僅僅是為了寫一些后端API接口推薦大家使用gin框架,今天我們就一起來學習一下Gin框架。

  博主推薦閱讀:
    https://beego.me/
    https://github.com/gin-gonic/gin

2>.Gin框架概述

  gin是使用golang開發的web框架.簡單易用,高性能(是httprouter的40倍),適用於生產環境

  gin特點如下:
    快:
      路由使用基數樹,低內存,不使用反射;     中間件注冊:
      一個請求可以被一系列的中間件和最后的action處理     奔潰處理:
      gin可以捕獲panic使應用程序可用     JSON校驗:
      將請求的數據轉換為JSON並校驗     路由組:
      更好的組織路由的方式,無限制嵌套而不影響性能     錯誤管理:
      可以收集所有的錯誤     內建渲染方式:
      JSON,XML和HTML渲染方式     可繼承:
      簡單的去創建中間件

3>.Gin框架運行原理

  MVC模型如下所示:
    模型(Model):
      數據庫管理與設計。
    控制器(Controller):
      處理用戶輸入的信息,負責從視圖讀取數據,控制用戶輸入,並向模型發送數據源,是應用程序中處理用戶交互的部分,負責管理與用戶交互控制。
    視圖(View):
      將信息顯示給用戶。

  Gin框架的運行流程如下圖所示。

4>.Gin和Beego框架對比

  MVC:
    Gin框架不完全支持,而beego完全支持。

  Web功能:
    Gin框架支持的不全面,比如Gin框架不是支持正則路由,不支持session。而beego支持的很全面。

  使用場景:
    Gin適合使用在封裝API接口,而beego適合web項目。

5>.安裝Gin組件

go get  github.com/gin-gonic/gin

6>.Hello World案例

package main

import "github.com/gin-gonic/gin"

func main() {
    /**
    所有的接口都要由路由來進行管理。
        Gin的路由支持GET,POST,PUT,DELETE,PATCH,HEAD,OPTIONS等請求
        同時還有一個Any函數,可以同時支持以上的所有請求。

    創建路由(router)並引入默認中間件
        在源碼中,首先是New一個engine,緊接着通過Use方法傳入了Logger()和Recovery()這兩個中間件。
        其中 Logger 是對日志進行記錄,而 Recovery 是對有 painc時, 進行500的錯誤處理。

    創建路由(router)無中間件
        router := gin.New()
    */
    router := gin.Default()

    //定義路由的GET方法及響應的處理函數
    router.GET("/hello", func(c *gin.Context) {
        //將發送的消息封裝成JSON發送給瀏覽器
        c.JSON(200, gin.H{
            //這是咱們定義的數據
            "message": "Hello World!",
        })
    })

    //啟動路由並指定監聽的地址及端口,若不指定默認監聽0.0.0.0:8080
    router.Run("127.0.0.1:9000")
}
案例代碼

 

二.Gin框架快速入門案例

1>.路由分組

package main

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

func main() {
    /**
    所有的接口都要由路由來進行管理。
        Gin的路由支持GET,POST,PUT,DELETE,PATCH,HEAD,OPTIONS等請求
        同時還有一個Any函數,可以同時支持以上的所有請求。

    創建路由(router)並引入默認中間件
        在源碼中,首先是New一個engine,緊接着通過Use方法傳入了Logger()和Recovery()這兩個中間件。
        其中 Logger 是對日志進行記錄,而 Recovery 是對有 painc時, 進行500的錯誤處理。

    創建路由(router)無中間件
        router := gin.New()
    */
    router := gin.Default()

    /**
    路由分組:
        在大型項目中,會經常使用到路由分組技術。
        路由分組有點類似於Django創建各種app,其目的就是將項目有組織的划分成多個模塊。
    */
    //定義group1路由組
    group1 := router.Group("group1")
    {
        group1.GET("/login", func(context *gin.Context) {
            context.String(http.StatusOK, "<h1>Login successful</h1>")
        })
    }

    //定義group2路由組
    group2 := router.Group("group2")
    {
        group2.GET("/logout", func(context *gin.Context) {
            context.String(http.StatusOK, "<h3>Logout</h3>")
        })
    }

    //啟動路由並指定監聽的地址及端口,若不指定默認監聽0.0.0.0:8080
    router.Run("127.0.0.1:9000")
}
案例代碼

2>.獲取GET方法參數

package main

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

func main() {
    /**
    所有的接口都要由路由來進行管理。
        Gin的路由支持GET,POST,PUT,DELETE,PATCH,HEAD,OPTIONS等請求
        同時還有一個Any函數,可以同時支持以上的所有請求。

    創建路由(router)並引入默認中間件
        在源碼中,首先是New一個engine,緊接着通過Use方法傳入了Logger()和Recovery()這兩個中間件。
        其中 Logger 是對日志進行記錄,而 Recovery 是對有 painc時, 進行500的錯誤處理。

    創建路由(router)無中間件
        router := gin.New()
    */
    router := gin.Default()

    router.GET("/blog", func(context *gin.Context) {
        //獲取GET方法參數
        user := context.Query("user")
        //獲取GET方法帶默認值參數,如果沒有則返回默認值"yinzhengjie"
        passwd := context.DefaultQuery("passwd", "yinzhengjie")
        //將獲取到的數據返回給客戶端
        context.String(http.StatusOK, fmt.Sprintf("%s:%s\n", user, passwd))
    })

    //啟動路由並指定監聽的地址及端口,若不指定默認監聽0.0.0.0:8080
    router.Run("172.30.100.101:9000")
}
案例代碼

3>.獲取路徑中的參數

package main

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

func main() {
    /**
    所有的接口都要由路由來進行管理。
        Gin的路由支持GET,POST,PUT,DELETE,PATCH,HEAD,OPTIONS等請求
        同時還有一個Any函數,可以同時支持以上的所有請求。

    創建路由(router)並引入默認中間件
        在源碼中,首先是New一個engine,緊接着通過Use方法傳入了Logger()和Recovery()這兩個中間件。
        其中 Logger 是對日志進行記錄,而 Recovery 是對有 painc時, 進行500的錯誤處理。

    創建路由(router)無中間件
        router := gin.New()
    */
    router := gin.Default()

    /**
    ":user"
        表示user字段必須存在,否則會報錯404。
    "*passwd":
        表示action字段可以存在或不存在。
    */
    router.GET("/blog/:user/*passwd", func(context *gin.Context) {
        //獲取路徑中的參數
        user := context.Param("user")
        passwd := context.Param("passwd")
        //將獲取到的數據返回給客戶端
        context.String(http.StatusOK, fmt.Sprintf("%s:%s\n", user, passwd))
    })

    //啟動路由並指定監聽的地址及端口,若不指定默認監聽0.0.0.0:8080
    router.Run("172.30.100.101:9000")
}
案例代碼

4>.獲取POST方法參數

package main

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

func main() {
    /**
    所有的接口都要由路由來進行管理。
        Gin的路由支持GET,POST,PUT,DELETE,PATCH,HEAD,OPTIONS等請求
        同時還有一個Any函數,可以同時支持以上的所有請求。

    創建路由(router)並引入默認中間件
        在源碼中,首先是New一個engine,緊接着通過Use方法傳入了Logger()和Recovery()這兩個中間件。
        其中 Logger 是對日志進行記錄,而 Recovery 是對有 painc時, 進行500的錯誤處理。

    創建路由(router)無中間件
        router := gin.New()
    */
    router := gin.Default()

    router.POST("/blog", func(context *gin.Context) {
        //從POST方法獲取參數
        user := context.PostForm("user")
        //獲取POST方法帶默認值參數,如果沒有則返回默認值"yinzhengjie"
        passwd := context.DefaultPostForm("passwd", "yinzhengjie")
        //將獲取到的數據返回給客戶端
        context.JSON(http.StatusOK, gin.H{
            "status": "POST",
            "USER":   user,
            "PASSWD": passwd,
        })
    })

    //啟動路由並指定監聽的地址及端口,若不指定默認監聽0.0.0.0:8080
    router.Run("172.30.100.101:9000")
}
案例代碼

5>.單文件上傳

package main

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

func main() {
    /**
    所有的接口都要由路由來進行管理。
        Gin的路由支持GET,POST,PUT,DELETE,PATCH,HEAD,OPTIONS等請求
        同時還有一個Any函數,可以同時支持以上的所有請求。

    創建路由(router)並引入默認中間件
        在源碼中,首先是New一個engine,緊接着通過Use方法傳入了Logger()和Recovery()這兩個中間件。
        其中 Logger 是對日志進行記錄,而 Recovery 是對有 painc時, 進行500的錯誤處理。

    創建路由(router)無中間件
        router := gin.New()
    */
    router := gin.Default()

    // 給表單限制上傳大小 (默認 32 MiB)
    // router.MaxMultipartMemory = 8 << 20  // 配置8MiB

    router.POST("/upload", func(c *gin.Context) {
        // 單文件
        file, _ := c.FormFile("file")
        log.Println(file.Filename)

        //底層采用流拷貝(io.Copy)技術,將上傳文件到指定的路徑
        //c.SaveUploadedFile(file, dst)

        c.String(http.StatusOK, fmt.Sprintf("'%s' uploaded!", file.Filename))
    })

    //啟動路由並指定監聽的地址及端口,若不指定默認監聽0.0.0.0:8080
    router.Run("172.30.100.101:9000")

    /**
    使用curl命令測試:
        [root@yinzhengjie.com ~]# curl -X POST http://172.30.100.101:9000/upload   -F "file=@/root/dpt"   -H "Content-Type: multipart/form-data"

    */
}
案例代碼

6>.多文件上傳

package main

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

func main() {
    /**
    所有的接口都要由路由來進行管理。
        Gin的路由支持GET,POST,PUT,DELETE,PATCH,HEAD,OPTIONS等請求
        同時還有一個Any函數,可以同時支持以上的所有請求。

    創建路由(router)並引入默認中間件
        在源碼中,首先是New一個engine,緊接着通過Use方法傳入了Logger()和Recovery()這兩個中間件。
        其中 Logger 是對日志進行記錄,而 Recovery 是對有 painc時, 進行500的錯誤處理。

    創建路由(router)無中間件
        router := gin.New()
    */
    router := gin.Default()

    // 給表單限制上傳大小 (默認 32 MiB)
    // router.MaxMultipartMemory = 8 << 20  // 配置8MiB

    router.POST("/upload", func(c *gin.Context) {
        // 多文件
        form, _ := c.MultipartForm()
        files := form.File["upload[]"]

        for _, file := range files {
            log.Println(file.Filename)
            //底層采用流拷貝(io.Copy)技術,將上傳文件到指定的路徑
            // c.SaveUploadedFile(file, dst)
        }
        c.String(http.StatusOK, fmt.Sprintf("%d files uploaded!", len(files)))
    })

    //啟動路由並指定監聽的地址及端口,若不指定默認監聽0.0.0.0:8080
    router.Run("172.30.100.101:9000")

    /**
    使用curl命令測試:
        [root@yinzhengjie.com ~]# curl -X POST http://172.30.100.101:9000/upload   -F "upload[]=@/etc/issue"   -F "upload[]=@/etc/passwd"   -H "Content-Type: multipart/form-data"
    */
}
案例代碼

7>.模型綁定

package main

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

type Login struct {
    /**
    模型綁定:
        若要將請求主體綁定到結構體中,請使用模型綁定,目前支持JSON、XML、YAML和標准表單值(foo=bar&boo=baz)的綁定。
        需要在綁定的字段上設置tag,比如,綁定格式為json,需要這樣設置 json:"fieldname" 。
        你還可以給字段指定特定規則的修飾符,如果一個字段用binding:"required"修飾,並且在綁定時該字段的值為空,那么將返回一個錯。
        程序通過tag區分你傳遞參數的數據格式,從而自動解析相關參數.
    */
    User   string `form:"user" json:"user" xml:"user"  binding:"required"`
    Passwd string `form:"passwd" json:"passwd" xml:"passwd"  binding:"required"`
}

func main() {
    /**
    所有的接口都要由路由來進行管理。
        Gin的路由支持GET,POST,PUT,DELETE,PATCH,HEAD,OPTIONS等請求
        同時還有一個Any函數,可以同時支持以上的所有請求。

    創建路由(router)並引入默認中間件
        在源碼中,首先是New一個engine,緊接着通過Use方法傳入了Logger()和Recovery()這兩個中間件。
        其中 Logger 是對日志進行記錄,而 Recovery 是對有 painc時, 進行500的錯誤處理。

    創建路由(router)無中間件
        router := gin.New()
    */
    router := gin.Default()

    router.POST("/login", func(context *gin.Context) {
        //定義接收請求的數據
        var login_user Login

        /**
        Gin還提供了兩套綁定方法:
            Must bind:
                Methods - Bind, BindJSON, BindXML, BindQuery, BindYAML Behavior:
                    這些方法底層使用MustBindWith,如果存在綁定錯誤,請求將被以下指令中止 c.AbortWithError(400, err).SetType(ErrorTypeBind),
                    響應狀態代碼會被設置為400,請求頭Content-Type被設置為text/plain; charset=utf-8。
                    注意,如果你試圖在此之后設置響應代碼,將會發出一個警告 [GIN-debug] [WARNING] Headers were already written. Wanted to override status code 400 with 422。
                    如果你希望更好地控制行為,請使用ShouldBind相關的方法。

            Should bind
                Methods - ShouldBind, ShouldBindJSON, ShouldBindXML, ShouldBindQuery, ShouldBindYAML Behavior:
                    這些方法底層使用 ShouldBindWith,如果存在綁定錯誤,則返回錯誤,開發人員可以正確處理請求和錯誤。
                    當我們使用綁定方法時,Gin會根據Content-Type推斷出使用哪種綁定器,如果你確定你綁定的是什么,你可以使用MustBindWith或者BindingWith。
        */
        err := context.ShouldBind(&login_user)
        //如果綁定出錯了就將錯誤信息直接發送給前端頁面.
        if err != nil {
            context.JSON(http.StatusBadRequest, gin.H{
                "Error": err.Error(),
            })
        }
        //將結構體綁定后,如果沒有報錯就可以解析到相應數據,此時我們驗證用戶名和密碼,驗證成功返回200狀態碼,驗證失敗返回401狀態碼
        if login_user.User == "yinzhengjie" && login_user.Passwd == "123" {
            context.JSON(http.StatusOK, gin.H{
                "Status": "Login successful\n",
            })
        } else {
            context.JSON(http.StatusUnauthorized, gin.H{
                "Status": "Login failed\n",
            })
        }
    })

    //啟動路由並指定監聽的地址及端口,若不指定默認監聽0.0.0.0:8080
    router.Run("172.30.100.101:9000")

    /**
    使用curl命令進行測試:
        [root@yinzhengjie.com ~]# curl -X POST   http://172.30.100.101:9000/login   -H 'content-type: application/json'   -d '{ "user": "yinzhengjie","passwd":"123"}'

    */
}
案例代碼

 

三.response及中間件

1>.什么是Context

  Context作為一個數據結構在中間件中傳遞本次請求的各種數據、管理流程,進行響應在請求來到服務器后,Context對象會生成用來串流程。

2>.響應(response)周期

  整個響應(response)周期:
    (1)路由,找到處理函數(handle)     (2)將請求和響應用Context包裝起來供業務代碼使用     (3)依次調用中間件和處理函數     (4)輸出結果   因為golang原生為web而生而提供了完善的功能,用戶需要關注的東西大多數是業務邏輯本身了。
  gin能做的事情也是去把ServeHTTP(ResponseWriter,
*Request)做得高效、友好。一個請求來到服務器了,ServeHTTP會被調用。

3>.設置返回數據

 

4>.自定義中間件

package main

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

/**
自定義一個中間件功能:
    返回的包頭(header)信息有咱們自定義的包頭信息。
*/
func ResponseHeaders() gin.HandlerFunc {
    return func(context *gin.Context) {
        //自定義包頭信息
        context.Header("Access-Control-Allow-Origin", "*")
        context.Header("Access-Control-Allow-Headers", "Content-Type,AccessToken,X-CRSF-Token,Authorization,Token")
        context.Header("Access-Control-Allow-Methods", "POST,GET,DELETE,OPTIONS")
        context.Header("Access-Control-Expose-Headers", "Content-Length,Access-Control-Allow-Origin,Access-Control-Allow-Headers,Content-Type")
        context.Header("Access-Control-Allow-Credentials", "true")
        //使用"context.Next()"表示繼續調用其它的內置中間件,也可以立即終止調用其它的中間件使用"context.Abort()"
        context.Next()

    }
}

func main() {
    /**
    所有的接口都要由路由來進行管理。
        Gin的路由支持GET,POST,PUT,DELETE,PATCH,HEAD,OPTIONS等請求
        同時還有一個Any函數,可以同時支持以上的所有請求。

    創建路由(router)並引入默認中間件
        在源碼中,首先是New一個engine,緊接着通過Use方法傳入了Logger()和Recovery()這兩個中間件。
        其中 Logger 是對日志進行記錄,而 Recovery 是對有 painc時, 進行500的錯誤處理。

    創建路由(router)無中間件
        router := gin.New()
    */
    router := gin.Default()

    //綁定咱們自己定義的中間件
    router.Use(ResponseHeaders())

    router.GET("/middle", func(context *gin.Context) {
        context.String(http.StatusOK, "Response OK\n")
    })

    //啟動路由並指定監聽的地址及端口,若不指定默認監聽0.0.0.0:8080
    router.Run("172.30.100.101:9000")

    /**
    使用curl命令測試:
        [root@yinzhengjie.com ~]# curl -v   http://172.30.100.101:9000/middle
    */
}
案例代碼

5>.自定義日志中間件

package main

import (
    "fmt"
    "github.com/gin-gonic/gin"
    "io"
    "net/http"
    "os"
    "time"
)

func main() {
    /**
    所有的接口都要由路由來進行管理。
        Gin的路由支持GET,POST,PUT,DELETE,PATCH,HEAD,OPTIONS等請求
        同時還有一個Any函數,可以同時支持以上的所有請求。

    創建路由(router)並引入默認中間件
        router := gin.Default()
        在源碼中,首先是New一個engine,緊接着通過Use方法傳入了Logger()和Recovery()這兩個中間件。
        其中 Logger 是對日志進行記錄,而 Recovery 是對有 painc時, 進行500的錯誤處理。

    創建路由(router)無中間件
        router := gin.New()
    */
    router := gin.New()

    //創建一個日志文件
    f, _ := os.Create("gin.log")

    //默認數據寫入到終端控制台(os.Stdout),我們需要將日志寫到咱們剛剛創建的日志文件中
    gin.DefaultWriter = io.MultiWriter(f)

    //自定義你的日志格式
    logger := func(params gin.LogFormatterParams) string {
        return fmt.Sprintf("%s - [%s] \"%s %s %s %d %s \"%s\" %s\"\n",
            //客戶端IP
            params.ClientIP,
            //請求時間
            params.TimeStamp.Format(time.RFC1123),
            //請求方法
            params.Method,
            //請求路徑
            params.Path,
            //請求協議
            params.Request.Proto,
            //請求的狀態碼
            params.StatusCode,
            //請求延遲(耗時)
            params.Latency,
            //請求的客戶端類型
            params.Request.UserAgent(),
            //請求的錯誤信息
            params.ErrorMessage,
        )
    }

    //LoggerWithFormatter 中間件會將日志寫入 gin.DefaultWriter
    router.Use(gin.LoggerWithFormatter(logger))

    router.GET("/log", func(context *gin.Context) {
        context.String(http.StatusOK, "自定義日志中間件\n")
    })

    //啟動路由並指定監聽的地址及端口,若不指定默認監聽0.0.0.0:8080
    router.Run("172.30.100.101:9000")

}
案例代碼

[GIN-debug] GET    /log                      --> main.main.func2 (2 handlers)
[GIN-debug] Listening and serving HTTP on 172.30.100.101:9000
172.30.100.101 - [Fri, 15 May 2020 06:23:42 CST] "GET /log HTTP/1.1 200 0s "curl/7.29.0" "
172.30.100.101 - [Fri, 15 May 2020 06:23:43 CST] "GET /log HTTP/1.1 200 0s "curl/7.29.0" "
172.30.100.101 - [Fri, 15 May 2020 06:23:46 CST] "GET /log HTTP/1.1 200 0s "curl/7.29.0" "
172.30.100.101 - [Fri, 15 May 2020 06:23:47 CST] "GET /log HTTP/1.1 200 0s "curl/7.29.0" "
172.30.100.101 - [Fri, 15 May 2020 06:23:48 CST] "GET /log HTTP/1.1 200 0s "curl/7.29.0" "
gin.log

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM