Go Web輕量級框架Gin學習系列:數據綁定

原創做者,公衆號【程序員讀書】,歡迎關注公衆號,轉載文章請註明出處哦。html

前面寫了兩篇與Gin框架學習有關的文章,主要講了Gin框架的安裝,定義處理HTTP請求的各類方法以及如何根據客戶端需求返回不一樣格式的數據,但這中間漏了一個環節,那就是返回數據以前,如何獲取客戶端HTTP請求中帶上來的參數,關於這點,咱們就在這篇文章中講一講。程序員

Gin框架將處理HTTP請求參數以及如何響應等操做都封裝到了gin.Conetxt結構體,併爲gin.Context提供了很是多的方法,所以瞭解gin.Context的結構定義與方法,對使用Gin框架編寫Web項目很是重要。json

下面是gin.Context結構定義代碼:數組

type Context struct {
    Request *http.Request
    Writer  ResponseWriter
    Params Params
    // 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
    // contains filtered or unexported fields
}
複製代碼

從上面的gin.Context的結構定義來看,gin.Context封裝了http.Requesthttp.ResponseWriter安全

獲取請求參數

1. Path

path是指請求的url中域名以後從/開始的部分,如掘金首頁地址:https://juejin.im/timeline/timeline部分即是path,可使用gin.Context中的Param()方法獲取這部分參數。bash

func (c *Context) Param(key string) string
複製代碼

使用Param()方法獲取path中的參數:服務器

r.GET("/user/:id",func(c *gin.Context){
    id := c.Param("id")
})
複製代碼

除了使用gin.Context的中Param()方法外,還能夠用gin.Context中的Params字段獲取到path中的參數,Params的定義以下:數據結構

type Params []Param
func (ps Params) ByName(name string) (va string)
func (ps Params) Get(name string) (string, bool)
複製代碼

使用gin.Context中的Params字段獲取path中的參數示例以下:app

r.GET("/user/:id",func(c *gin.Context){
    id,err := c.Params.Get("id")
    //id := c.Params.ByName("id")
})
複製代碼

2. Query

query是指url請求地址中的問號後面的部,稱爲查詢參數,以下面地址中,query=%E6%96%87%E7%AB%A0&type=all就是查詢參數。框架

https://juejin.im/search?query=%E6%96%87%E7%AB%A0&type=all
複製代碼

gin.Context提供瞭如下幾個方法,用於獲取Query部分的參數。

1. 獲取單個參數
func (c *Context) GetQuery(key string) (string, bool)
func (c *Context) Query(key string) string
func (c *Context) DefaultQuery(key, defaultValue string) string
複製代碼

上面三個方法用於獲取單個數值,GetQueryQuery多返回一個error類型的參數,實際上Query方法只是封裝了GetQuery方法,並忽略GetQuery方法返回的錯誤而已,而DefaultQuery方法則在沒有獲取相應參數值的返回一個默認值。

示例以下:

r.GET("/user", func(c *gin.Context) {
    id,_ := c.GetQuery("id")
    //id := c.Query("id")
    //id := c.DefaultQuery("id","10")
    c.JSON(200,id)
})
複製代碼

請求:http://localhost:8080/user?id=11

響應:11

2. 獲取數組

GetQueryArray方法和QueryArray的區別與GetQuery和Query的類似。

func (c *Context) GetQueryArray(key string) ([]string, bool)
func (c *Context) QueryArray(key string) []string

複製代碼

示例以下:

r.GET("/user", func(c *gin.Context) {
    ids := c.QueryArray("id")
    //id,_ := c.QueryArray("id")
    c.JSON(200,ids)
})
複製代碼

請求:http://localhost:8080/user?id=10&id=11&id=12

響應:["10","11","12"]

3. 獲取map

GetQueryArray方法和QueryArray的區別與GetQuery和Query的類似。

func (c *Context) QueryMap(key string) map[string]string
func (c *Context) GetQueryMap(key string) (map[string]string, bool)
複製代碼

示例以下:

r.GET("/user", func(c *gin.Context) {
    ids := c.QueryMap("ids")
    //ids,_ := c.GetQueryMap("ids")
    c.JSON(200,ids)
})
複製代碼

請求:http://localhost:8080/user?ids[10]=zhang

響應:{"10":"zhang"}

3. Body

通常HTTP的Post請求參數都是經過body部分傳給服務器端的,尤爲是數據量大或安全性要求較高的數據,如登陸功能中的帳號密碼等參數。

gin.Context提供瞭如下四個方法讓咱們獲取body中的數據,不過要說明的是,下面的四個方法,只能獲取Content-typeapplication/x-www-form-urlencodedmultipart/form-databody中的數據。

下面方法的使用方式與上面獲取Query的方法使用類型,區別只是數據來源不一樣而已,這裏便再也不寫示例程序。

func (c *Context) PostForm(key string) string
func (c *Context) PostFormArray(key string) []string
func (c *Context) PostFormMap(key string) map[string]string
func (c *Context) DefaultPostForm(key, defaultValue string) string
func (c *Context) GetPostForm(key string) (string, bool)
func (c *Context) GetPostFormArray(key string) ([]string, bool)
func (c *Context) GetPostFormMap(key string) (map[string]string, bool)
func (c *Context) GetRawData() ([]byte, error)
複製代碼

數據綁定

在前面的例子中,咱們直接使用gin.Context提供的方法獲取請求中經過pathquerybody帶上來的參數,但使用前面的那些方法,並不能處理請求中比較複雜的數據結構,好比Content-type爲application/json或application/xml時,其所帶上的數據會很複雜,所以咱們須要使用另一種方法獲取這些數據,這種方式叫數據綁定

Gin框架將數據綁定的操做都封裝在gin/binding這個包中,下面是gin/binding包定義的常量,說明gin/binding包所支持的Content-type格式。

const (
    MIMEJSON              = "application/json"
    MIMEHTML              = "text/html"
    MIMEXML               = "application/xml"
    MIMEXML2              = "text/xml"
    MIMEPlain             = "text/plain"
    MIMEPOSTForm          = "application/x-www-form-urlencoded"
    MIMEMultipartPOSTForm = "multipart/form-data"
    MIMEPROTOBUF          = "application/x-protobuf"
    MIMEMSGPACK           = "application/x-msgpack"
    MIMEMSGPACK2          = "application/msgpack"
    MIMEYAML              = "application/x-yaml"
)
複製代碼

gin.binding包也定義處理不一樣Content-type提交數據的處理結構體,並以變量的形式讓其餘包能夠訪問,以下:

var (
    JSON          = jsonBinding{}
    XML           = xmlBinding{}
    Form          = formBinding{}
    Query         = queryBinding{}
    FormPost      = formPostBinding{}
    FormMultipart = formMultipartBinding{}
    ProtoBuf      = protobufBinding{}
    MsgPack       = msgpackBinding{}
    YAML          = yamlBinding{}
    Uri           = uriBinding{}
)
複製代碼

但實際上,咱們並不須要調用gin/binding包的代碼來完成數據綁定的功能,由於gin.Context中已經在gin.Context的基礎上封裝了許多更加快捷的方法供咱們使用:

gin.Context封裝的相關綁定方法,分爲以Bind爲前綴的系列方法和以ShouldBind爲前綴的系列方法,這兩個系列方法之間的差異在於以Bind爲前綴的方法,在用戶輸入數據不符合相應格式時,會直接返回http狀態爲400的響應給客戶端。

以Bind爲前綴的系列方法

1. Path
func (c *Context) BindUri(obj interface{}) error
複製代碼

代碼示例:

type User struct {
    Uid      int    //用戶id
    Username string //用戶名
}
func main() {
    r := gin.Default()
    r.GET("/bind/:uid/username", func(c *gin.Context) {
        var u User
        e := c.BindUri(&u)
        if e == nil{
            c.JSON(200,u)
        }
    })
    r.Run()
}

複製代碼

請求:http://localhost:8080/bind/1/小張

輸入:{1,"小張"}

2. Query
func (c *Context) BindQuery(obj interface{}) error
複製代碼

代碼示例:

r.GET("/bind/:uid/username", func(c *gin.Context) {
    var u User
    e := c.BindQuery(&u)
    if e == nil{
        c.JSON(200,u)
    }
})
複製代碼

請求:http://localhost:8080/bind?uid=1&username=小張

輸出:{1,"小張"}

3. Body

當咱們在HTTP請求中Body設置不一樣數據格式,須要設置相應頭部Content-Type的值,比較經常使用爲jsonxmlyamlgin.Context提供下面三個方法綁定對應Content-type時body中的數據。

func (c *Context) BindJSON(obj interface{}) error
func (c *Context) BindXML(obj interface{}) error
func (c *Context) BindYAML(obj interface{}) error
複製代碼

除了上面三個方法外,更經常使用的Bind()方法,Bind()方法會自動根據Content-Type的值選擇不一樣的綁定類型。

func (c *Context) Bind(obj interface{}) error
複製代碼

示例

r.POST("bind",func(c *gin.Context){
    u := User{}
    c.Bind(&u)
})
複製代碼

上面幾個方法都是獲取固定Content-type或自動根據Content-type選擇綁定類型,咱們也可使用下面兩個方法自行選擇綁定類型。

下面兩個方法的第二個參數值是gin.binding中定義好的常量,咱們在上面講過。

func (c *Context) BindWith(obj interface{}, b binding.Binding) error
func (c *Context) MustBindWith(obj interface{}, b binding.Binding) error
複製代碼

示例

r.POST("bind",func(c *gin.Context){
	u := User{}
	c.BindWith(&u,binding.JSON)
    c.MustBindWith(&u,binding.JSON)
})
複製代碼

以ShouldBind爲前綴的系列方法

以ShouldBind爲前綴的相應的方法與以Bind爲前綴的方法使用基本相同,所以下面沒有相應演示的代碼。

1. Path
func (c *Context) ShouldBindUri(obj interface{}) error
複製代碼
2. Query
func (c *Context) ShouldBindQuery(obj interface{}) error
複製代碼
3. Body
func (c *Context) ShouldBind(obj interface{}) error
func (c *Context) ShouldBindJSON(obj interface{}) error
func (c *Context) ShouldBindXML(obj interface{}) error
func (c *Context) ShouldBindYAML(obj interface{}) error
func (c *Context) ShouldBindBodyWith(obj interface{}, bb binding.BindingBody) (err error)
func (c *Context) ShouldBindWith(obj interface{}, b binding.Binding) error
複製代碼

小結

Gin框架在net/http包的基礎上封裝了許多的方法,讓咱們能夠接收客戶端傳遞上來的各類不一樣格式的數據,可是從客戶端獲得的數據以後,仍是要驗證數據是否合法或是否咱們想要的,這是Gin框架中有關數據驗證器的知識了,有機會再寫寫這方面的文章。


你的關注,是我寫做路上最大的鼓勵!

相關文章
相關標籤/搜索