使用 Go 读写请求

帅气猫咪 · · 1142 次点击 · · 开始浏览    
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

简介

使用 web 框架, 最基础的事情就是读写请求了,
Gin 支持很多种类的请求参数, 也支持多种格式的响应.

读取请求参数

path 中的参数

使用 Param() 可以获取 path 中的参数.

定义在 path 中的参数有两种格式, 一个是 :name 的以冒号开头的,
另一种是 *action 的以星号开头的.

:name 是必定匹配的, 一定要有值, 不能为空. 下面的代码中, 第一个例子就是如此,
:name 来表示用户的名字, 这样就可以在路径中表示任意的用户名了.

*action 是可选的, 如果不存在, 就会忽略掉, 比如是可以匹配到 /user/john/ 的,
另外 /user/john 会被跳转到 /user/john/.

// 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 中的参数

使用 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) })

from 中的参数

对于 form (表单) 中的参数, 也有和 query 类似的方法, PostFormDefaultPostForm.

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, }) })

模型绑定

上面的几种获取参数的方式都比较常规, 我觉得最有用的就是 模型绑定 了.

模型绑定首先要定义一个结构体 struct, struct 需要设置相应的 tag, 就是那些在反引号 ` 里面的字段,
然后就可以用对应的数据填充这个 struct 了, 也就是绑定.

// 绑定 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


有疑问加站长微信联系(非本文作者)

本文来自:Segmentfault

感谢作者:帅气猫咪

查看原文:使用 Go 读写请求

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

1142 次点击  
加入收藏 微博
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传