使用 web 框架, 最基礎的事情就是讀寫請求了,
Gin 支持不少種類的請求參數, 也支持多種格式的響應.github
使用 Param()
能夠獲取 path 中的參數.web
定義在 path 中的參數有兩種格式, 一個是 :name
的以冒號開頭的,
另外一種是 *action
的以星號開頭的.json
:name
是一定匹配的, 必定要有值, 不能爲空. 下面的代碼中, 第一個例子就是如此,
用 :name
來表示用戶的名字, 這樣就能夠在路徑中表示任意的用戶名了.框架
*action
是可選的, 若是不存在, 就會忽略掉, 好比是能夠匹配到 /user/john/
的,
另外 /user/john
會被跳轉到 /user/john/
.post
// This handler will match /user/john but will not match /user/ or /user router.GET("/user/:name", func(c *gin.Context) { name := c.Param("name") c.String(http.StatusOK, "Hello %s", name) }) // However, this one will match /user/john/ and also /user/john/send // If no other routers match /user/john, it will redirect to /user/john/ router.GET("/user/:name/*action", func(c *gin.Context) { name := c.Param("name") action := c.Param("action") message := name + " is " + action c.String(http.StatusOK, message) })
使用 Query()
和 DefaultQuery()
能夠獲取 query 中的參數,
後者使用第二個參數做爲默認值.性能
// Query string parameters are parsed using the existing underlying request object. // The request responds to a url matching: /welcome?firstname=Jane&lastname=Doe router.GET("/welcome", func(c *gin.Context) { firstname := c.DefaultQuery("firstname", "Guest") lastname := c.Query("lastname") // shortcut for c.Request.URL.Query().Get("lastname") c.String(http.StatusOK, "Hello %s %s", firstname, lastname) })
對於 form (表單) 中的參數, 也有和 query 相似的方法, PostForm
和 DefaultPostForm
.ui
router.POST("/form_post", func(c *gin.Context) { message := c.PostForm("message") nick := c.DefaultPostForm("nick", "anonymous") c.JSON(200, gin.H{ "status": "posted", "message": message, "nick": nick, }) })
上面的幾種獲取參數的方式都比較常規, 我以爲最有用的就是 模型綁定 了.this
模型綁定首先要定義一個結構體 struct, struct 須要設置相應的 tag, 就是那些在反引號 ` 裏面的字段,
而後就能夠用對應的數據填充這個 struct 了, 也就是綁定.url
// 綁定 JSON type Login struct { User string `form:"user" json:"user" xml:"user" binding:"required"` Password string `form:"password" json:"password" xml:"password" binding:"required"` } // 綁定 JSON ({"user": "manu", "password": "123"}) router.POST("/loginJSON", func(c *gin.Context) { var json Login if err := c.ShouldBindJSON(&json); err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) return } if json.User != "manu" || json.Password != "123" { c.JSON(http.StatusUnauthorized, gin.H{"status": "unauthorized"}) return } c.JSON(http.StatusOK, gin.H{"status": "you are logged in"}) }) // 綁定 XML ( // <?xml version="1.0" encoding="UTF-8"?> // <root> // <user>user</user> // <password>123</password> // </root>) router.POST("/loginXML", func(c *gin.Context) { var xml Login if err := c.ShouldBindXML(&xml); err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) return } if xml.User != "manu" || xml.Password != "123" { c.JSON(http.StatusUnauthorized, gin.H{"status": "unauthorized"}) return } c.JSON(http.StatusOK, gin.H{"status": "you are logged in"}) }) // 綁定 HTML 表單 (user=manu&password=123) router.POST("/loginForm", func(c *gin.Context) { var form Login // 根據 Content-Type Header 推斷使用哪一個綁定器。 if err := c.ShouldBind(&form); err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) return } if form.User != "manu" || form.Password != "123" { c.JSON(http.StatusUnauthorized, gin.H{"status": "unauthorized"}) return } c.JSON(http.StatusOK, gin.H{"status": "you are logged in"}) })
上面的代碼顯示了三種不一樣的綁定, 分別是綁定 JSON 格式的請求體, XML 格式的請求體和普通的表單.
對於 query 也是使用 form
tag 進行標記.
另外也能夠綁定 Header (使用 header
tag) 和 Uri (使用 uri
tag) 等.
對於請求, 也有多種類型的數據響應格式, 支持 XML, JSON, YAML 和 ProtoBuf.
func main() { r := gin.Default() // gin.H is a shortcut for map[string]interface{} r.GET("/someJSON", func(c *gin.Context) { c.JSON(http.StatusOK, gin.H{"message": "hey", "status": http.StatusOK}) }) r.GET("/moreJSON", func(c *gin.Context) { // You also can use a struct var msg struct { Name string `json:"user"` Message string Number int } msg.Name = "Lena" msg.Message = "hey" msg.Number = 123 // Note that msg.Name becomes "user" in the JSON // Will output : {"user": "Lena", "Message": "hey", "Number": 123} c.JSON(http.StatusOK, msg) }) r.GET("/someXML", func(c *gin.Context) { c.XML(http.StatusOK, gin.H{"message": "hey", "status": http.StatusOK}) }) r.GET("/someYAML", func(c *gin.Context) { c.YAML(http.StatusOK, gin.H{"message": "hey", "status": http.StatusOK}) }) r.GET("/someProtoBuf", func(c *gin.Context) { reps := []int64{int64(1), int64(2)} label := "test" // The specific definition of protobuf is written in the testdata/protoexample file. data := &protoexample.Test{ Label: &label, Reps: reps, } // Note that data becomes binary data in the response // Will output protoexample.Test protobuf serialized data c.ProtoBuf(http.StatusOK, data) }) // Listen and serve on 0.0.0.0:8080 r.Run(":8080") }
對於 API 服務來講, 這些已經足夠用了, 主要仍是用 JSON 格式的輸出.
若是須要高性能, 可使用 ProtoBuf, 但這不是人類易讀的, 因此一般
來講 JSON 足以知足要求.
主要介紹瞭如何使用 Gin 讀取請求, 並返回響應.
這部分是 web 框架的基礎, 框架的好用與否很大程度上
取決於這部分.
做爲版本 v0.6.0