淺談Gin框架中bind的使用
概述
Gin框架中,有bind函數(shù)可以非常方便的將url的查詢參數(shù)query parameter、http的Header,body中提交上來的數(shù)據(jù)格式,如form,json,xml等,綁定到go中的結(jié)構(gòu)體中去,這期間Binding做了啥事情,這么多個Bindding函數(shù),我們該如何選擇,一起通過源碼來解開其中神秘的面紗吧。
Binding接口
type Binding interface {
Name() string
Bind(*http.Request, interface{}) error
}
Binding是一個接口,在源碼中,有10個實現(xiàn)了Binding的結(jié)構(gòu)體,以及3個接口
?
context.Bind
// Bind checks the Content-Type to select a binding engine automatically,
// Depending the "Content-Type" header different bindings are used:
// "application/json" --> JSON binding
// "application/xml" --> XML binding
// otherwise --> returns an error.
// It parses the request's body as JSON if Content-Type == "application/json" using JSON or XML as a JSON input.
// It decodes the json payload into the struct specified as a pointer.
// It writes a 400 error and sets Content-Type header "text/plain" in the response if input is not valid.
func (c *Context) Bind(obj interface{}) error {
b := binding.Default(c.Request.Method, c.ContentType())
return c.MustBindWith(obj, b)
}
cnotext.MustBindWith
// MustBindWith binds the passed struct pointer using the specified binding engine.
// It will abort the request with HTTP 400 if any error occurs.
// See the binding package.
func (c *Context) MustBindWith(obj interface{}, b binding.Binding) error {
if err := c.ShouldBindWith(obj, b); err != nil {
c.AbortWithError(http.StatusBadRequest, err).SetType(ErrorTypeBind) // nolint: errcheck
return err
}
return nil
}
從注解和源碼可以看出,MustBindWith最終也是調(diào)用了SouldBindWith,并且對ShouldBindWith的結(jié)果進行了判斷,如果有錯誤,則以http 400的狀態(tài)碼進行退出。
ShouldBindWith
// ShouldBindWith binds the passed struct pointer using the specified binding engine.
// See the binding package.
func (c *Context) ShouldBindWith(obj interface{}, b binding.Binding) error {
return b.Bind(c.Request, obj)
}
這個方法是所有其他綁定方法的一個基礎(chǔ),基本上所有的綁定方法都需要用到這個方法來對數(shù)據(jù)結(jié)構(gòu)進行一個綁定
以上為主要的bingding的過程,其他派生出來的如BindJSON、ShouldBindJSON等,為具體的數(shù)據(jù)類型的快捷方式而已,只是幫我們把具體的bingding的數(shù)據(jù)類型提前給封裝了起來而已,如Json格式的bingding函數(shù)
context.BindJSON
// BindJSON is a shortcut for c.MustBindWith(obj, binding.JSON).
func (c *Context) BindJSON(obj interface{}) error {
return c.MustBindWith(obj, binding.JSON)
}
context.BindJSON從源碼上分析,可以看到,僅僅比Bind方法少了一句
b := binding.Default(c.Request.Method, c.ContentType())
這一句是為了判斷當(dāng)前的請求方法和contentType,來給context.MustBindWith傳的一個具體的bingding類型。
Json的實現(xiàn)的Binding接口如下
func (jsonBinding) Bind(req *http.Request, obj interface{}) error {
if req == nil || req.Body == nil {
return fmt.Errorf("invalid request")
}
return decodeJSON(req.Body, obj)
}
jsonBinding結(jié)構(gòu)體實現(xiàn)了Binding接口的Bind方法,將請求過來的Body數(shù)據(jù)進行解碼,綁定到obj里面去
context.ShouldBindJSON
// ShouldBindJSON is a shortcut for c.ShouldBindWith(obj, binding.JSON).
func (c *Context) ShouldBindJSON(obj interface{}) error {
return c.ShouldBindWith(obj, binding.JSON)
}
從源碼的注解來看,ShouldBindJSON其實就是ShouldBindWith(obj, binding.JSON)的快捷方式,簡單來說,就是在ShouldBindWith(obj, binding.JSON)上面固定了參數(shù),當(dāng)我們明確規(guī)定,body提交的參數(shù)內(nèi)容為json時,簡化了我們的調(diào)用和增強了代碼的可讀性。
context.ShouldBindUri()
// ShouldBindUri binds the passed struct pointer using the specified binding engine.
func (c *Context) ShouldBindUri(obj interface{}) error {
m := make(map[string][]string)
for _, v := range c.Params {
m[v.Key] = []string{v.Value}
}
return binding.Uri.BindUri(m, obj)
}
從url綁定采用的方法跟header和body的方式不一樣,不需要傳入一個實現(xiàn)Binding接口的結(jié)構(gòu)體類型
context.ShouldBindUri()
// BindUri binds the passed struct pointer using binding.Uri.
// It will abort the request with HTTP 400 if any error occurs.
func (c *Context) BindUri(obj interface{}) error {
if err := c.ShouldBindUri(obj); err != nil {
c.AbortWithError(http.StatusBadRequest, err).SetType(ErrorTypeBind) // nolint: errcheck
return err
}
return nil
}
BindUri也是對ShouldBindUri的一個封裝,多了一個對ShouldBindUri結(jié)果的一個判斷 代碼實例
代碼如下
package main
import (
"github.com/gin-gonic/gin"
"net/http"
)
type queryHeader struct {
Myheader string `header:"myheader"`
Mydemo string `header:"mydemo"`
}
type queryBody struct {
Name string `json:"name"`
Age int `json:"age"`
Sex int `json:"sex"`
}
type queryParameter struct {
Year int `form:"year"`
Month int `form:"month"`
}
type queryUri struct {
Id int `uri:"id"`
Name string `uri:"name"`
}
func bindUri(context *gin.Context){
var q queryUri
err:= context.ShouldBindUri(&q)
if err != nil {
context.JSON(http.StatusBadRequest,gin.H{
"result":err.Error(),
})
return
}
context.JSON(http.StatusOK,gin.H{
"result":"綁定成功",
"uri": q,
})
}
func bindQuery(context *gin.Context){
var q queryParameter
err:= context.ShouldBindQuery(&q)
if err != nil {
context.JSON(http.StatusBadRequest,gin.H{
"result":err.Error(),
})
return
}
context.JSON(http.StatusOK,gin.H{
"result":"綁定成功",
"query": q,
})
}
func bindBody(context *gin.Context){
var q queryBody
err:= context.ShouldBindJSON(&q)
if err != nil {
context.JSON(http.StatusBadRequest,gin.H{
"result":err.Error(),
})
return
}
context.JSON(http.StatusOK,gin.H{
"result":"綁定成功",
"body": q,
})
}
func bindhead(context *gin.Context){
var q queryHeader
err := context.ShouldBindHeader(&q)
if err != nil {
context.JSON(http.StatusBadRequest,gin.H{
"result":err.Error(),
})
return
}
context.JSON(http.StatusOK,gin.H{
"result":"綁定成功",
"header": q,
})
}
func main(){
srv := gin.Default()
srv.GET("/binding/header",bindhead)
srv.GET("/binding/body",bindBody)
srv.GET("/binding/query",bindQuery)
srv.GET("/binding/:id/:name",bindUri)
srv.Run(":9999")
}
運行結(jié)果
綁定Header數(shù)據(jù)

綁定QueryParameter數(shù)據(jù)

綁定Body Json數(shù)據(jù)

綁定Uri數(shù)據(jù)

總結(jié)
- 使用gin框架中的bind方法,可以很容易對http請求過來的數(shù)據(jù)傳遞到我們的結(jié)構(gòu)體指針去,方便我們代碼編程。
- 當(dāng)參數(shù)比較簡單,不需要結(jié)構(gòu)體來進行封裝時候,此時還需采用context的其他方法來獲取對應(yīng)的值
- gin在bind的時候,未對結(jié)構(gòu)體的數(shù)據(jù)進行有效性檢查,如果對數(shù)據(jù)有強要求時,需要自己對結(jié)構(gòu)體的數(shù)據(jù)內(nèi)容進行判斷
- 建議在實踐過程中,使用shouldBind<xxx>函數(shù)
到此這篇關(guān)于淺談Gin框架中bind的使用的文章就介紹到這了,更多相關(guān)Gin框架中bind內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Golang Gorm實現(xiàn)自定義多態(tài)模型關(guān)聯(lián)查詢
GORM 是一個流行的開源 ORM (Object-Relational Mapping) 庫,專為 Go 語言設(shè)計,它簡化了與 SQL 數(shù)據(jù)庫的交互,GORM 封裝了數(shù)據(jù)庫操作,使得開發(fā)者能夠通過簡單的鏈式調(diào)用來執(zhí)行 CRUD,本文給大家介紹了Golang Gorm實現(xiàn)自定義多態(tài)模型關(guān)聯(lián)查詢,需要的朋友可以參考下2024-11-11
Go string轉(zhuǎn)int,int64,int32及注意事項說明
這篇文章主要介紹了Go string轉(zhuǎn)int,int64,int32及注意事項說明,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2024-07-07
golang 實現(xiàn)兩個結(jié)構(gòu)體復(fù)制字段
這篇文章主要介紹了golang 實現(xiàn)兩個結(jié)構(gòu)體復(fù)制字段,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2021-04-04

