首先咱們使用 go moudle來管理依賴, go版本要求在 1.11.1 及以上git
export GO111MODULE=on export GOPROXY=https://mirrors.aliyun.com/goproxy/ 複製代碼
初始化 mod 配置github
go mod init
>在當前目錄下會生成 go.mod 文件, 做爲依賴配置.
複製代碼
build項目後會自動下載依賴json
其中在實際項目中發現 goland 沒法識別項目代碼, 須要 在 goland 的 setting 裏設置啓用 Go Modulesapi
goland Preference -> Go -> Go Modules(vgo)
-> Enable Go Modules(vgo)intergration
複製代碼
package main import ( "github.com/gin-gonic/gin" ) func main() { r := gin.Default() // get 方式請求 r.GET("/get", func(c *gin.Context) { c.JSON(200, "get") }) // post 方式請求 r.POST("/post", func(c *gin.Context) { c.JSON(200, "post") }) // 任意類型請求 r.Any("any", func(c *gin.Context) { c.JSON(200, "any") }) // handle 指定方式請求 r.Handle("POST", "/handle_post", func(c *gin.Context) { c.JSON(200, "handle post") }) //r.Run(":8888") 監聽 8888 端口 r.Run() } 複製代碼
這裏咱們定義了經常使用的 get post方法, 經過 debug 能夠看到 any 方式爲咱們建立了全部的能夠實用的請求的方式, 最後使用了 handle 方式指定方法參數. gin.Default 配置默認的參數, Run 啓動 http 服務, 默認監聽 8080 端口bash
curl -XPOST http://127.0.0.1:8080/post output: "post" curl -XPOST http://127.0.0.1:8080/handle_post output: "handle post" 複製代碼
gin 的路由同請求方式下不能重複定義, 不然啓動將會異常退出markdown
package main import ( "github.com/gin-gonic/gin" "net/http" ) func main() { r := gin.Default() // get 方式請求 r.GET("/getUser/:uid", func(c *gin.Context) { c.JSON(http.StatusOK, gin.H{ "uid": c.Param("uid"), }) }) r.Run() } 複製代碼
output:app
curl http://127.0.0.1:8080/getUser/1451 output: {"uid":"1451"} 複製代碼
http.StatusOK 引用的 net/http 包中的狀態碼定義, c.Param() 獲取 uid 的值curl
在工做中咱們但願路由匹配到某個前綴oop
r.GET("/user/*a", func(c *gin.Context) { c.String(http.StatusOK, "hello user") }) 複製代碼
這樣只要請求到 user 就能夠攔截到了, 注意在 gin 裏是不容許再設置相似 /user/admin 這樣的路由了. 這裏是沒有路由優先級的.post
請求參數默認值
r.GET("/user", func(c *gin.Context) { c.JSON(http.StatusOK, gin.H{ "name": c.Query("name"), "sex": c.DefaultQuery("sex", "女"), }) }) 複製代碼
請求示例
curl http://127.0.0.1:8080/user?name=1 output: {"name":"1","sex":"女"} 複製代碼
獲取post方式請求的參數
c.String(http.StatusOK, c.PostForm("name")) //獲取name值, 默認值爲小明 c.String(http.StatusOK, c.DefaultPostForm("name", "小明") 複製代碼
r.POST("/user", func(c *gin.Context) { bodyBytes, error := ioutil.ReadAll(c.Request.Body) if error != nil { c.String(http.StatusOK, error.Error()) c.Abort() } c.String(http.StatusOK, string(bodyBytes)) }) 複製代碼
curl -XPOST http://127.0.0.1:8080/user?name=1 -d {"name":1} output: {name:1} 複製代碼
可是經過 readAll 讀取後再獲取值是獲取不到的. 解決方案就是再將值寫回去.
package main import ( "github.com/gin-gonic/gin" "net/http" ) type requestUser struct { Name string `form:"name"` Uid int `form:"uid"` Age int `form:"age"` Date time.Time `form:"date"` } func main() { r := gin.Default() r.POST("/user", userAction) r.Run() } func userAction(c *gin.Context) { var requestUser requestUser //這裏是根據請求的content-type進行解析(能夠解析json) if err := c.ShouldBind(&requestUser); err != nil { c.String(http.StatusOK, err.Error()) c.Abort() } c.String(http.StatusOK, "%v", requestUser) } 複製代碼
curl -XPOST http://127.0.0.1:8080/user -d 'name=xiaoming&age=23' output: {xiaoming 0 23} curl -XPOST http://127.0.0.1:8080/user -d 'name=xiaoming&date=2019-01-01' output: parsing time "2019-01-01" as "2006-01-02T15:04:05Z07:00": cannot parse "" as "T"{xiaoming 0 0 0001-01-01 00:00:00 +0000 UTC} 複製代碼
注意咱們在傳遞時間格式的時候解析發生錯誤.
這裏咱們須要定義時間格式結構體解決
type requestUser struct { Name string `form:"name"` Uid int `form:"uid"` Age int `form:"age"` Date time.Time `form:"date" time_format:"2006-01-02"` } 複製代碼
type requestUser struct { Name string `form:"name" binding:"required,len=10"` Uid int `form:"uid"` Age int `form:"age" binding:"required,gt=10"` } 複製代碼
curl -H "Content-Type:application/json" -XPOST http://127.0.0.1:8080/user -d '{"name":"xiaoming234342342342342","age":11}' output: Key: 'requestUser.Name' Error:Field validation for 'Name' failed on the 'len' tag{xiaoming234342342342342 0 11} 複製代碼
更多驗證規則: godoc.org/gopkg.in/go…
###自定義 validator
type requestUser struct { Name string `form:"name" binding:"required,len=10"` Uid int `form:"uid" binding:"checkUidAvailable"` Age int `form:"age" binding:"required,gt=10"` } 複製代碼
編寫 checkUidAvailable
// Structure func checkUidAvailable(field validator.FieldLevel) bool { if fieldValue, ok := field.Field().Interface().(int); ok { //隨機機率 if rand.Intn(2) == fieldValue { return true } } return false } 複製代碼
在 main方法中綁定
func main() { r := gin.Default() r.POST("/user", userAction) //綁定 if v, ok := binding.Validator.Engine().(*validator.Validate); ok { v.RegisterValidation("checkUidAvailable", checkUidAvailable) } r.Run() } 複製代碼
方法執行, ShouldBind 自動驗證
func userAction(c *gin.Context) { var requestUser requestUser if err := c.ShouldBind(&requestUser); err != nil { c.String(http.StatusInternalServerError, err.Error()) c.Abort() return } c.String(http.StatusOK, "%v", requestUser) } 複製代碼
f, _ := os.Create("gin.log") gin.DefaultWriter = io.MultiWriter(f) gin.DefaultErrorWriter = io.MultiWriter(f) r := gin.New() r.Use(gin.Logger(), gin.Recovery()) 複製代碼
上面咱們使用了 gin.New 實例的方式聲明, r.Use使用了兩個中間件, 一個爲日誌, 另外一個爲碰見 panic 拋出異常最上層, 讓程序正常運行.
f, _ := os.Create("gin.log") gin.DefaultWriter = io.MultiWriter(f) gin.DefaultErrorWriter = io.MultiWriter(f) r := gin.Default() 複製代碼
默認日誌是輸出到控制檯, 將日誌和錯誤日誌所有輸出到 gin.log
func ipAuthMiddleWare() gin.HandlerFunc { return func(c *gin.Context) { ipList := []string{ "127.0.0.1", } flag := false clientIp := c.ClientIP() for _, host := range ipList { if clientIp != host { flag = true break } } if !flag { c.String(http.StatusOK, "error") c.Abort() } } } --- r.Use(gin.Logger(), gin.Recovery(), ipAuthMiddleWare()) 複製代碼
api := r.Group("/api") { api.GET("user", userAction) } 複製代碼
訪問 127.0.0.1:8080/api/user 路由組中引入中間件
api := r.Group("/api").Use(ipAuthMiddleWare()) { api.GET("user", userAction) } 複製代碼
一樣使用 use 便可
json處理: colobu.com/2017/06/21/…