<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      Gin框架系列04:趣談參數(shù)綁定與校驗(yàn)

      導(dǎo)讀

      在第二節(jié),我們學(xué)習(xí)了Gin框架的路由定義與參數(shù)接收,今天應(yīng)一位同學(xué)的要求,來講解一下參數(shù)的綁定與校驗(yàn)。

      為什么校驗(yàn)參數(shù)?

      本不必拋出這個問題的,但顧及到初出茅廬的同學(xué),這里解釋一下。

      file

      假設(shè)做一個注冊接口,傳過來的用戶名是不是不能太騷氣?比如一堆空格和符號之類的;密碼是不是不能太長也不能太短?手機(jī)號是不是要符合規(guī)則?性別是不是不能填人妖?

      file

      另外,登錄的時候我們也需要驗(yàn)證賬號密碼是不是正確的,那么為了方便上手,咱就先來個簡單示例,做登錄驗(yàn)證。

      激情演示

      做登錄之前得先想清楚需要對用戶名密碼做什么樣的限制,比如他們都不能為空、用戶名只能是字母或數(shù)字、密碼長度只能在6位到12位之間等,如果各位看官沒有異議,接下來我就拿上述的這幾個條件來演示了。

      file

      定義結(jié)構(gòu)體與接口

      首先得有個地方存接收到的用戶名、密碼參數(shù),那就定一個名叫Login的結(jié)構(gòu)體吧。

      type Login struct {
      	User     string
      	Password string
      }
      

      然后再定義一個登錄接口,這塊不知道啥意思的同學(xué)可以去看我的第二篇教程。

      router.POST("/login", func(c *gin.Context) {
      
      })
      

      接口是定了,怎么才能把接收的參數(shù)放到Login結(jié)構(gòu)體里去呢?

      file

      綁定參數(shù)

      我們?nèi)シ幌?code>gin.Context下面都有些什么好東西可以拿來用。看到了一個叫做Bind的東東,官方說它可以自動根據(jù)Content-Type設(shè)置的值解析請求過來的參數(shù),然后把參數(shù)設(shè)置到結(jié)構(gòu)體里。

      func (c *Context) Bind(obj interface{}) error {
      	b := binding.Default(c.Request.Method, c.ContentType())
      	return c.MustBindWith(obj, b)
      }
      

      哇塞,這就有意思了,調(diào)用一下試試。記得把Login的引用傳過去,畢竟人家還要賦值的。

      router.POST("/login", func(c *gin.Context) {
        var login Login
        c.Bind(&login)
        c.JSON(200, login)
      })
      

      果不其然,跑起來的同學(xué)應(yīng)該可以發(fā)現(xiàn),它失敗了,并沒有取到我想要的參數(shù)值。

      curl -d "user=pingye&password=123" http://localhost:8080/login
      {"User":"","Password":""}
      

      這不對啊,不是說好做彼此的天使嗎?

      file

      不行,我要一層一層剝開gin框架是怎么處理的。

      file

      綁定失敗,剖析源碼

      經(jīng)過長達(dá)60分鐘的精心研究,我終于發(fā)現(xiàn)了終極奧義,先把我繪制的圖貼上。

      file

      事情是這樣的,我們調(diào)用的Bind方法實(shí)際調(diào)用了兩個方法binding.Defaultc.MustBindWith,前者的主要作用是根據(jù)終端請求的Content-Type選擇處理器,沒辦法,gin太強(qiáng),支持的類型太多了。我們剛才的請求方式被理所應(yīng)當(dāng)?shù)姆峙浣o了formBinding。

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

      然后呢?在拿到了formBinding之后,就來到了c.MustBindWith方法,它的作用就是調(diào)用formBinding的Bind方法,原來這哥們就是個中間商在賺差價。

      func (formBinding) Bind(req *http.Request, obj interface{}) error {
      	if err := req.ParseForm(); err != nil {
      		return err
      	}
      	if err := req.ParseMultipartForm(defaultMemory); err != nil {
      		if err != http.ErrNotMultipart {
      			return err
      		}
      	}
      	if err := mapForm(obj, req.Form); err != nil {
      		return err
      	}
      	return validate(obj)
      }
      

      Bind方法主要就干了兩件事情,第一是解析傳過來的表單參數(shù),第二是找到結(jié)構(gòu)體里的tagform進(jìn)行匹配賦值。看到這里我就明白了,原來只需要在Login后面加上一個tag。

      繼續(xù)綁定參數(shù)

      那我們加上tag試一下。

      type Login struct {
      	User     string `form:"user"`
      	Password string `form:"password"`
      }
      

      跑起來果然很完美。

      curl -d "user=pingye&password=123" http://localhost:8080/login
      {"User":"pingye","Password":"123"}
      

      看到了這里,聰明的你應(yīng)該涌出了很多想法,剛才說支持那么多類型,前端傳的是json咋搞呢?同學(xué)們可以自己試一下,現(xiàn)有的這套代碼啥都不用改就可以解析json,因?yàn)閖sonBinding并沒有去Login結(jié)構(gòu)體找tag,所以不用在后面加上json:"user"的標(biāo)識。

      curl -H "Content-Type:application/json" -d '{"user":"pingye","password":"123455"}' http://localhost:8080/login
      {"User":"pingye","Password":"123455"}
      

      至于其他的類型,同學(xué)們可以自己去動手試驗(yàn)一下,我們必須得到參數(shù)驗(yàn)證環(huán)節(jié)了。

      參數(shù)驗(yàn)證

      OK,這就到了激動人心的參數(shù)驗(yàn)證時刻了,再回顧一下剛才的需求,用戶名和密碼不能為空,用戶名只能是英文和數(shù)字,密碼長度必須得在6到12位。

      gin官方給出的示例是直接在tag中加校驗(yàn)規(guī)則,比如不能為空,就加上binding:"required"

      type Login struct {
      	User     string `form:"user" binding:"required"`
      	Password string `form:"password" binding:"required"`
      }
      

      在驗(yàn)證的地方也做一下處理,Bind會自動幫我們進(jìn)行校驗(yàn),如果校驗(yàn)失敗會返回一個error,我們把它輸出即可。

      router.POST("/login", func(c *gin.Context) {
        var login Login
        err := c.Bind(&login)
        if err != nil {
          c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
          return
        }
        c.JSON(200, login)
      })
      

      放心,參數(shù)驗(yàn)證的演示不會就這么結(jié)束的。

      file

      鑒于官方文檔給的信息太少了,我們還是通過源碼去找更多線索吧,通過源代碼可以看到,gin的參數(shù)驗(yàn)證實(shí)際上并不是自己實(shí)現(xiàn)的,而是使用了一個叫做go-playground/validator的庫。

      .
      ├── LICENSE
      ├── Makefile
      ├── README.md
      ├── _examples
      ├── baked_in.go
      ├── benchmarks_test.go
      ├── cache.go
      ├── doc.go
      ├── errors.go
      ├── field_level.go
      ├── go.mod
      ├── go.sum
      ├── logo.png
      ├── non-standard
      ├── regexes.go
      ├── struct_level.go
      ├── testdata
      ├── translations
      ├── translations.go
      ├── util.go
      ├── validator.go
      ├── validator_instance.go
      └── validator_test.go
      
      4 directories, 19 files
      

      里面有一個叫做doc.go的文件,有非常多的示例與解釋,簡直找到寶藏了,去他的官方文檔。

      file

      我在里面找到了長度限制的demo,很簡單,min和max兩個標(biāo)簽就搞定了。跑一下完全沒有問題。

      type Login struct {
      	User     string `form:"user" binding:"required"`
      	Password string `form:"password" binding:"required,min=6,max=12"`
      }
      
      curl -d "user=pingye&password=12345" http://localhost:8080/login 
      {"error":"Key: 'Login.Password' Error:Field validation for 'Password' failed on the 'min' tag"}
      
      curl -d "user=pingye&password=1234567890123" http://localhost:8080/login
      {"error":"Key: 'Login.Password' Error:Field validation for 'Password' failed on the 'max' tag"}
      

      實(shí)現(xiàn)了兩個校驗(yàn)了,還剩下用戶名的字母和數(shù)字限制,讓我震驚的是,我以為隨便說的這個限制要用多種組合來實(shí)現(xiàn),竟然輕松就找到了一個對應(yīng)的,簡直太棒了(強(qiáng)烈推薦這個庫,看來后面有必要出一期這個庫的介紹),很簡單,加上一個名叫alphanum的規(guī)則就可以實(shí)現(xiàn)了。

      type Login struct {
      	User     string `form:"user" binding:"required,alphanum"`
      	Password string `form:"password" binding:"required,min=6,max=12"`
      }
      

      今天我的任務(wù)結(jié)束了,各位是不是需要查看源碼,來吧來吧,點(diǎn)擊查看源碼,順便STAR一下我哈。


      Go語言庫示例開源項(xiàng)目「golang-examples」歡迎star~

      https://github.com/pingyeaa/golang-examples
      

      感謝大家的觀看,如果覺得文章對你有所幫助,歡迎關(guān)注公眾號「平也」,聚焦Go語言與技術(shù)原理。
      關(guān)注我

      posted @ 2020-04-10 17:02  MARIOOW  閱讀(6726)  評論(0)    收藏  舉報
      主站蜘蛛池模板: 日韩在线视频网| 人人妻人人添人人爽日韩欧美| 免费观看全黄做爰大片国产| 国产精品一二区在线观看 | 国产精品中文字幕在线看| 国产精品亚洲精品日韩已满十八小 | 国产精品中文字幕免费| 毛片网站在线观看| 噜噜噜噜私人影院| 麻豆国产尤物av尤物在线观看 | 蜜臀av色欲a片无人一区| 五月丁香啪啪| 国产又爽又大又黄a片| 国产在热线精品视频99公交| 色九月亚洲综合网| 久久精品国产99精品国产2021| 中文字幕日韩区二区三区| 国产精品人成在线观看免费| 亚洲人成人网站色www| 青草99在线免费观看| 风流老熟女一区二区三区| 免青青草免费观看视频在线| 18禁无遮挡啪啪无码网站破解版| 任我爽精品视频在线播放 | 精品免费国产一区二区三区四区| 国产av综合一区二区三区| 欧美成人精品手机在线| 亚洲精品无码成人aaa片 | 国产福利永久在线视频无毒不卡| 国产在线视频导航| 免费无码成人AV片在线| 亚洲国产成人精品无色码| 国产精品+日韩精品+在线播放| 亚洲偷自拍国综合| 免费人成在线观看品爱网| 日韩欧美视频一区二区三区| 欧美在线观看www| 国产精品国产精品无卡区| 亚洲熟女精品一区二区| 岳池县| 亚洲日韩中文字幕在线播放|