淺談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個實(shí)現(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é)果進(jìn)行了判斷,如果有錯誤,則以http 400的狀態(tài)碼進(jìn)行退出。
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)進(jìn)行一個綁定
以上為主要的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的實(shí)現(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)體實(shí)現(xiàn)了Binding接口的Bind方法,將請求過來的Body數(shù)據(jù)進(jìn)行解碼,綁定到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其實(shí)就是ShouldBindWith(obj, binding.JSON)的快捷方式,簡單來說,就是在ShouldBindWith(obj, binding.JSON)上面固定了參數(shù),當(dāng)我們明確規(guī)定,body提交的參數(shù)內(nèi)容為json時(shí),簡化了我們的調(diào)用和增強(qiáng)了代碼的可讀性。
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的方式不一樣,不需要傳入一個實(shí)現(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é)果的一個判斷 代碼實(shí)例
代碼如下
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") }
運(yùn)行結(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)體來進(jìn)行封裝時(shí)候,此時(shí)還需采用context的其他方法來獲取對應(yīng)的值
- gin在bind的時(shí)候,未對結(jié)構(gòu)體的數(shù)據(jù)進(jìn)行有效性檢查,如果對數(shù)據(jù)有強(qiáng)要求時(shí),需要自己對結(jié)構(gòu)體的數(shù)據(jù)內(nèi)容進(jìn)行判斷
- 建議在實(shí)踐過程中,使用shouldBind<xxx>函數(shù)
到此這篇關(guān)于淺談Gin框架中bind的使用的文章就介紹到這了,更多相關(guān)Gin框架中bind內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
使用Gin框架搭建一個Go Web應(yīng)用程序的方法詳解
在本文中,我們將要實(shí)現(xiàn)一個簡單的 Web 應(yīng)用程序,通過 Gin 框架來搭建,主要支持用戶注冊和登錄,用戶可以通過注冊賬戶的方式創(chuàng)建自己的賬號,并通過登錄功能進(jìn)行身份驗(yàn)證,感興趣的同學(xué)跟著小編一起來看看吧2023-08-08goroutine?泄漏和避免泄漏實(shí)戰(zhàn)示例
這篇文章主要為大家介紹了goroutine?泄漏和避免泄漏實(shí)戰(zhàn)示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-12-12輕松構(gòu)建Go應(yīng)用的Dockerfile
本文介紹了如何制作一個用于構(gòu)建和運(yùn)行Go應(yīng)用程序的Docker鏡像的Dockerfile的相關(guān)資料,需要的朋友可以參考下2023-10-10Golang中文字符串截取函數(shù)實(shí)現(xiàn)原理
在golang中可以通過切片截取一個數(shù)組或字符串,但是當(dāng)截取的字符串是中文時(shí),可能會出現(xiàn)問題,下面我們來自定義個函數(shù)解決Golang中文字符串截取問題2018-03-03GoLang職責(zé)鏈模式代碼實(shí)現(xiàn)介紹
這篇文章主要介紹了GoLang職責(zé)鏈模式代碼實(shí)現(xiàn),職責(zé)鏈模式是一種常用的設(shè)計(jì)模式,可以提高代碼的靈活性與可維護(hù)性,職責(zé)鏈模式將請求和處理分離,可以讓請求在處理鏈中依次經(jīng)過多個處理者,直到找到能夠處理請求的處理者為止2023-05-05深入分析Go?實(shí)現(xiàn)?MySQL?數(shù)據(jù)庫事務(wù)
本文深入分析了Go語言實(shí)現(xiàn)MySQL數(shù)據(jù)庫事務(wù)的原理和實(shí)現(xiàn)方式,包括事務(wù)的ACID特性、事務(wù)的隔離級別、事務(wù)的實(shí)現(xiàn)方式等。同時(shí),本文還介紹了Go語言中的事務(wù)處理機(jī)制和相關(guān)的API函數(shù),以及如何使用Go語言實(shí)現(xiàn)MySQL數(shù)據(jù)庫事務(wù)。2023-06-06Golang 操作TSV文件的實(shí)戰(zhàn)示例
本文主要介紹了Golang 操作TSV文件的實(shí)戰(zhàn)示例,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-03-03