Gin 框架怎么實(shí)現(xiàn)驗(yàn)證請(qǐng)求參數(shù)和返回響應(yīng)數(shù)據(jù)的函數(shù)?
1.介紹
在使用 Gin 框架開發(fā)時(shí),入口函數(shù)通常需要支持驗(yàn)證請(qǐng)求參數(shù)和返回響應(yīng)數(shù)據(jù)。
我們可以將驗(yàn)證請(qǐng)求參數(shù)和返回響應(yīng)數(shù)據(jù)整合為一個(gè)通用函數(shù)。
然后,結(jié)合響應(yīng)數(shù)據(jù)返回中間件,實(shí)現(xiàn)通過一個(gè)函數(shù),實(shí)現(xiàn)驗(yàn)證請(qǐng)求參數(shù)和返回響應(yīng)數(shù)據(jù) 的功能。
2.請(qǐng)求參數(shù)驗(yàn)證和返回響應(yīng)數(shù)據(jù)
首先,我們需要定義一個(gè)自定義結(jié)構(gòu)體類型 Response,示例代碼:
type Response struct {
Code int `json:"code"`
Msg string `json:"msg"`
Data map[string]interface{} `json:"data"`
}
閱讀上面這段代碼,我們定義一個(gè)自定義結(jié)構(gòu)體類型 Response,該結(jié)構(gòu)體類型包含 3 個(gè)字段,分別是 Code,Msg,Data,并且分別定義了 json 標(biāo)簽。
需要注意的是,字段 Data 使用的變量類型是 map[string]interface{},映射的 value 使用 interface{} 變量類型,可以支持任意類型的響應(yīng)數(shù)據(jù)。
此外,我們還可以根據(jù)項(xiàng)目需求,添加其它字段,比如 TraceId,Error 等。
返回響應(yīng)數(shù)據(jù)
接下來,我們創(chuàng)建一個(gè)返回響應(yīng)數(shù)據(jù)的函數(shù),示例代碼:
func GetData(c *gin.Context) (data *Response) {
value, exists := c.Get("data")
if !exists {
data = &Response{
Code: http.StatusOK,
}
data.Data = make(map[string]interface{})
c.Set("data", data)
return
}
if data, exists = value.(*Response); !exists {
data = &Response{Code: http.StatusInternalServerError}
return
}
return
}
閱讀上面這段代碼,我們使用 Gin 框架的 gin.Context 的存儲(chǔ)數(shù)據(jù),通過 Set 和 Get 方法,設(shè)置和獲取數(shù)據(jù)。
需要注意的是,使用 gin.Context 存儲(chǔ)的數(shù)據(jù)是 interface{} 類型,所以,在我們使用該數(shù)據(jù)時(shí),需要先通過斷言,檢查該數(shù)據(jù)的類型是否合法。
請(qǐng)求參數(shù)驗(yàn)證
接下來,我們創(chuàng)建一個(gè)驗(yàn)證請(qǐng)求參數(shù)和返回響應(yīng)數(shù)據(jù)的函數(shù) ValidatorAndReturn,示例代碼:
func ValidatorAndReturn(c *gin.Context, arg interface{}) (data *Response, err error) {
data = GetData(c)
err = c.ShouldBind(arg)
if err != nil {
return
}
return
}
閱讀上面這段代碼,我們定義一個(gè)函數(shù),接收參數(shù)是 *gin.Context 類型的變量 c,和 interface{} 類型的變量 arg,返回結(jié)果是 *Response 類型的 data 和 error 類型的 err。
函數(shù)體中,包含自定義函數(shù) GetData 和 ShouldBind 方法。讀者朋友們,可以根據(jù)自己的項(xiàng)目,優(yōu)化驗(yàn)證請(qǐng)求參數(shù)的代碼。
需要注意的是,嚴(yán)格意義上講,此處 GetData 函數(shù)并未提供 Gin 框架入口函數(shù)自動(dòng)返回響應(yīng)數(shù)據(jù)的功能。我們需要通過中間件實(shí)現(xiàn)該功能。
3.響應(yīng)數(shù)據(jù)返回中間件
最后,我們需要?jiǎng)?chuàng)建一個(gè)中間件函數(shù) ResponseReturn,使 Gin 框架的入口函數(shù)自動(dòng)返回響應(yīng)數(shù)據(jù)。
示例代碼:
// ResponseReturn middleware
func ResponseReturn() gin.HandlerFunc {
return func(c *gin.Context) {
data := GetData(c)
c.Render(http.StatusOK, ReturnJson{Data: data})
}
}
閱讀上面這段代碼,我們定義一個(gè)中間件函數(shù) ResponseReturn,使用 gin.Context 的 Render 方法,返回響應(yīng)數(shù)據(jù)。
需要注意的是 Render 的第二個(gè)參數(shù)是 render.Render 類型。
源碼:
type Render interface {
Render(http.ResponseWriter) error
WriteContentType(w http.ResponseWriter)
}
閱讀 Gin 框架源碼,我們可以發(fā)現(xiàn) render.Render 是一個(gè)接口類型,包含兩個(gè)方法,分別是 Render 和 WriteContentType。
所以,我們定義了一個(gè)結(jié)構(gòu)體 ReturnJson,并實(shí)現(xiàn) render.Render 的兩個(gè)方法,示例代碼:
var contentType = []string{"application/json; charset=utf-8"}
type ReturnJson struct {
Data interface{}
}
func responseContentType(w http.ResponseWriter, contentType []string) {
header := w.Header()
if val := header["Content-Type"]; len(val) == 0 {
header["Content-Type"] = contentType
}
}
func ResponseJson(w http.ResponseWriter, data interface{}) (err error) {
responseContentType(w, contentType)
bf := bytes.NewBuffer([]byte{})
jsonEncoder := json.NewEncoder(bf)
jsonEncoder.SetEscapeHTML(false)
err = jsonEncoder.Encode(data)
if err != nil {
return
}
_, err = w.Write(bf.Bytes())
if err != nil {
return
}
return
}
func (r ReturnJson) Render(w http.ResponseWriter) (err error) {
err = ResponseJson(w, r.Data)
if err != nil {
return
}
return
}
func (r ReturnJson) WriteContentType(w http.ResponseWriter) {
responseContentType(w, contentType)
}
閱讀上面這段代碼,我們定義結(jié)構(gòu)體類型的自定義類型 ReturnJson,并創(chuàng)建兩個(gè)方法 Render 和 WriteContentType,從而實(shí)現(xiàn)接口類型 render.Render,作為 c.Render 的參數(shù)。
4.總結(jié)
本文我們介紹 Gin 框架怎么實(shí)現(xiàn)驗(yàn)證請(qǐng)求參數(shù)和返回響應(yīng)數(shù)據(jù)的函數(shù)。
我們通過三個(gè)步驟完成,第一,創(chuàng)建返回響應(yīng)數(shù)據(jù)的函數(shù);第二,創(chuàng)建驗(yàn)證請(qǐng)求參數(shù)和返回響應(yīng)數(shù)據(jù)的整合函數(shù);第三,創(chuàng)建返回響應(yīng)數(shù)據(jù)的中間件函數(shù)。
本文所用到的代碼,我們?cè)谥暗奈恼轮卸冀榻B過,讀者朋友們?nèi)绻胁幻靼椎拇a,可以翻閱之前的文章。