官方文档地址(中文):https://gin-gonic.com/zh-cn/docs/
注:没用过Gin的读者强烈建议先阅读第一节:Gin操作指南:开山篇。
本节演示GET绑定,包括绑定表单数据至自定义结构体,绑定查询字符串或表单数据,只绑定url查询字符串,查询字符串参数,设置和获取Cookie 从reader读取数据。在开始之前,我们需要在”02请求参数处理“目录下打开命令行,执行如下命令来创建子目录:
mkdir 绑定表单数据至自定义结构体 绑定查询字符串或表单数据 只绑定url查询字符串 查询字符串参数 设置和获取Cookie 从reader读取数据
然后下载安装postman,注册登录后,点击新建,如图
目录
- 一、绑定表单数据至自定义结构体
- 二、绑定查询字符串或表单数据
- 三、只绑定url查询字符串
- 四、查询字符串参数
- 五、从reader读取数据
- 六、设置和获取Cookie
一、绑定表单数据至自定义结构体
package main
import (
"github.com/gin-gonic/gin" // 引入 gin-gonic/gin 包,用于构建 HTTP 服务
)
// StructA 定义一个结构体,包含一个字段 FieldA,绑定表单字段 field_a
type StructA struct {
FieldA string `form:"field_a"` // 绑定来自表单数据的 field_a
}
// StructB 定义一个包含嵌套结构体和其他字段的结构体
type StructB struct {
NestedStruct StructA // 嵌套的 StructA 结构体
FieldB string `form:"field_b"` // 绑定来自表单数据的 field_b
}
// StructC 定义一个包含指向嵌套结构体的指针和其他字段的结构体
type StructC struct {
NestedStructPointer *StructA // 指向嵌套的 StructA 结构体的指针
FieldC string `form:"field_c"` // 绑定来自表单数据的 field_c
}
// StructD 定义一个包含嵌套匿名结构体和其他字段的结构体
type StructD struct {
NestedAnonyStruct struct {
FieldX string `form:"field_x"` // 绑定来自表单数据的 field_x
} // 嵌套的匿名结构体
FieldD string `form:"field_d"` // 绑定来自表单数据的 field_d
}
// GetDataB 处理 GET 请求,将表单数据绑定至 StructB,并返回 JSON 响应
func GetDataB(c *gin.Context) {
var b StructB // 创建 StructB 的实例
c.Bind(&b) // 将请求中的表单数据绑定到结构体 b
// 返回 JSON 响应,包含结构体 b 的字段
c.JSON(200, gin.H{
"a": b.NestedStruct, // 返回 NestedStruct
"b": b.FieldB, // 返回 FieldB
})
}
// GetDataC 处理 GET 请求,将表单数据绑定至 StructC,并返回 JSON 响应
func GetDataC(c *gin.Context) {
var b StructC // 创建 StructC 的实例
c.Bind(&b) // 将请求中的表单数据绑定到结构体 b
// 返回 JSON 响应,包含结构体 b 的字段
c.JSON(200, gin.H{
"a": b.NestedStructPointer, // 返回 NestedStructPointer
"c": b.FieldC, // 返回 FieldC
})
}
// GetDataD 处理 GET 请求,将表单数据绑定至 StructD,并返回 JSON 响应
func GetDataD(c *gin.Context) {
var b StructD // 创建 StructD 的实例
c.Bind(&b) // 将请求中的表单数据绑定到结构体 b
// 返回 JSON 响应,包含结构体 b 的字段
c.JSON(200, gin.H{
"x": b.NestedAnonyStruct, // 返回 NestedAnonyStruct
"d": b.FieldD, // 返回 FieldD
})
}
// main 函数设置路由并启动服务器
func main() {
r := gin.Default() // 创建默认的 Gin 路由引擎
// 设置路由,绑定处理函数
r.GET("/getb", GetDataB) // 处理 GET 请求 /getb
r.GET("/getc", GetDataC) // 处理 GET 请求 /getc
r.GET("/getd", GetDataD) // 处理 GET 请求 /getd
r.Run() // 启动服务器,监听默认端口 8080
}
效果
二、绑定查询字符串或表单数据
package main
import (
"log" // 引入 log 包,用于日志输出
"github.com/gin-gonic/gin" // 引入 gin-gonic/gin 包,用于构建 HTTP 服务
)
// 定义一个结构体 Person,用于绑定请求中的数据
type Person struct {
Name string `form:"name" json:"name"` // `form:"name"` 用于表单提交,`json:"name"` 用于 JSON 请求
Address string `form:"address" json:"address"` // `form:"address"` 用于表单提交,`json:"address"` 用于 JSON 请求
}
func main() {
route := gin.Default() // 创建一个 gin 路由实例,带有默认的日志和恢复中间件
// 处理 GET 请求的路由,访问 /testing 路由时,调用 startPage 函数处理请求
route.GET("/testing", startPage)
// 运行服务器,监听 8085 端口
route.Run(":8085")
}
// 处理请求的函数,绑定并处理表单和 JSON 数据
func startPage(c *gin.Context) {
var person Person // 定义 Person 结构体变量,用于接收绑定的数据
// 尝试从查询字符串中绑定数据 (name 和 address)
if c.Bind(&person) == nil { // c.Bind 自动根据请求的 Content-Type 选择合适的绑定方法
log.Println("====== Bind By Query String ======") // 绑定成功后,打印日志
log.Println(person.Name) // 打印绑定的 Name
log.Println(person.Address) // 打印绑定的 Address
}
// 尝试从 JSON 请求体中绑定数据
if c.BindJSON(&person) == nil { // 使用 BindJSON 方法,专门用于绑定 JSON 数据
log.Println("====== Bind By JSON ======") // 绑定成功后,打印日志
log.Println(person.Name) // 打印绑定的 Name
log.Println(person.Address) // 打印绑定的 Address
}
// 返回响应给客户端,状态码 200,内容为 "Success"
c.String(200, "Success")
}
通过查询字符串测试:
通过 Postman 发送 JSON 数据测试:
使用 Postman 创建一个新的请求,方法选择 GET,URL 为 http://localhost:8085/testing。
在 Body 选项卡中按下图设置,点击send即可看到效果:
三、只绑定url查询字符串
package main
import (
"log" // 引入 log 包,用于日志输出
"github.com/gin-gonic/gin" // 引入 gin-gonic/gin 包,用于创建 HTTP web 框架
)
// 定义一个 Person 结构体,用于接收查询参数中的 name 和 address
type Person struct {
Name string `form:"name"` // form:"name" 指定该字段从查询参数 name 中提取
Address string `form:"address"` // form:"address" 指定该字段从查询参数 address 中提取
}
func main() {
route := gin.Default() // 创建一个 Gin 实例,带有默认的日志和恢复中间件
// route.Any 注册一个处理所有 HTTP 方法(GET、POST、PUT 等)到 /testing 路由的处理器函数
route.Any("/testing", startPage)
// 监听并启动服务,监听的端口为 8085
route.Run(":8085")
}
// 处理请求的处理器函数
func startPage(c *gin.Context) {
var person Person // 创建一个 Person 结构体实例,用于接收请求中的数据
// 通过 BindQuery 绑定查询字符串参数,即从 URL 中的查询参数绑定 name 和 address
// 例如:/testing?name=John&address=NewYork
if c.BindQuery(&person) == nil { // 如果绑定没有出错,返回 nil
// 绑定成功后打印日志,输出绑定的 name 和 address
log.Println("====== Only Bind Query String ======") // 输出绑定信息的提示日志
log.Println(person.Name) // 输出绑定的 Name 值
log.Println(person.Address) // 输出绑定的 Address 值
}
// 返回 HTTP 状态码 200,和字符串 "Success" 作为响应内容
c.String(200, "Success")
}
效果
四、查询字符串参数
package main
import (
"net/http" // 导入 HTTP 包,用于处理 HTTP 状态码等
"github.com/gin-gonic/gin" // 导入 Gin 框架包,用于创建 HTTP Web 服务器
)
func main() {
// 使用 gin.Default() 创建一个默认的 Gin 路由器实例
// 默认情况下,包含了日志和恢复中间件(用于记录请求日志和处理服务器崩溃时的恢复)
router := gin.Default()
// 定义一个 GET 请求的路由处理函数,用于处理 "/welcome" 路由
// 这个路由会接收 URL 查询参数(Query Parameters),并返回个性化的响应
// 示例 URL:/welcome?firstname=Jane&lastname=Doe
router.GET("/welcome", func(c *gin.Context) {
// 使用 c.DefaultQuery 方法解析 URL 中的 "firstname" 查询参数
// 如果查询参数不存在,则返回默认值 "Guest"
firstname := c.DefaultQuery("firstname", "Guest")
// 使用 c.Query 方法获取 URL 中的 "lastname" 查询参数
// c.Query 是 c.Request.URL.Query().Get("lastname") 的简化版本
lastname := c.Query("lastname")
// 使用 c.String 返回一个字符串作为响应
// 其中包含 HTTP 状态码 http.StatusOK(即 200),并将解析出的 "firstname" 和 "lastname" 插入到响应消息中
// 如果查询参数没有提供,默认会使用 "Guest" 作为 firstname
c.String(http.StatusOK, "Hello %s %s", firstname, lastname)
})
// 运行 Gin 服务器,监听在本地的 8080 端口上
router.Run(":8080")
}
效果
五、从reader读取数据
package main
import (
"net/http" // 导入 HTTP 包,用于处理 HTTP 请求和响应
"github.com/gin-gonic/gin" // 导入 Gin 框架包,用于创建 HTTP Web 服务器
)
func main() {
// 使用 gin.Default() 创建一个默认的 Gin 路由器实例
router := gin.Default()
// 定义一个 GET 请求的路由处理函数,用于处理 "/someDataFromReader" 路由
// 这个路由会从远程 URL 获取数据,并通过 Gin 将该数据发送给客户端
router.GET("/someDataFromReader", func(c *gin.Context) {
// 使用 http.Get 方法发起 HTTP GET 请求,尝试从远程服务器获取图像文件
response, err := http.Get("https://img2.baidu.com/it/u=3545291696,228271590&fm=253&fmt=auto&app=138&f=JPEG?w=800&h=1186")
// 检查是否发生错误,或者返回的 HTTP 状态码是否不是 200 OK
// 如果发生错误或者状态码不是 200,则返回 HTTP 503 服务不可用状态
if err != nil || response.StatusCode != http.StatusOK {
c.Status(http.StatusServiceUnavailable)
return
}
// 获取响应的 Body(即图像文件的二进制数据)
reader := response.Body
// 获取文件的内容长度,用于设置响应头中的 Content-Length
contentLength := response.ContentLength
// 获取响应头中的 Content-Type,通常是文件的 MIME 类型(如 "image/png")
contentType := response.Header.Get("Content-Type")
// 定义额外的 HTTP 响应头,比如 "Content-Disposition" 设置为附件下载,并指定文件名为 "gopher.png"
extraHeaders := map[string]string{
"Content-Disposition": `attachment; filename="gopher.png"`, // 提示浏览器以下载的形式处理响应内容
}
// 使用 c.DataFromReader 向客户端发送数据
// 参数包括 HTTP 状态码 200 OK,文件的长度,文件的类型,数据流(即 reader),以及额外的 HTTP 响应头
c.DataFromReader(http.StatusOK, contentLength, contentType, reader, extraHeaders)
})
// 启动 Gin 服务器,监听在本地的 8080 端口
router.Run(":8080")
}
注意:官方文档给的url有问题,手动可以访问,但程序访问不了,这里随便在百度上找了一张图片的url。
效果:
六、设置和获取Cookie
package main
import (
"fmt" // 导入 fmt 包,用于格式化输出
"github.com/gin-gonic/gin" // 导入 Gin 框架
)
func main() {
// 创建一个默认的 Gin 路由
router := gin.Default()
// 定义 GET 请求的路由,当请求路径为 "/cookie" 时执行对应的处理函数
router.GET("/cookie", func(c *gin.Context) {
// 尝试获取名为 "gin_cookie" 的 Cookie
cookie, err := c.Cookie("gin_cookie")
// 如果没有找到 Cookie 或者发生错误
if err != nil {
// 设置默认值
cookie = "NotSet"
// 设置一个名为 "gin_cookie" 的 Cookie,有效期为 3600 秒
c.SetCookie("gin_cookie", "test", 3600, "/", "localhost", false, true)
}
// 打印 Cookie 的值
fmt.Printf("Cookie value: %s \n", cookie)
})
// 启动 HTTP 服务器,监听在默认端口 8080
router.Run()
}
打开浏览器,访问http://localhost:8080/cookie
首次访问时,会在控制台看到输出 Cookie value: NotSet
,按F12-网络,刷新页面,会看到有个名称为cookie的缓存,同时控制台的输出变为了Cookie value: test
,如图