Go Gin框架

8 min

:dancer: Gin前言

Gin 是一个流行的 Go 语言 Web 框架

:one: 处理前端传来的数据

1. 获取 URL 参数

URL 参数通常用于 GET 请求,可以通过 c.Param 获取。

  • Gin 框架中的 GET 请求,如果需要从 URL 中获取参数,则要在 URL 路由中指定参数。这些参数在 URL 中以冒号 : 开头
r.GET("/user/:name", func(c *gin.Context) {
    name := c.Param("name")
    c.String(http.StatusOK, "Hello %s", name)
})

2. 获取 Query 参数

Query 参数也是用于 GET 请求,可以通过 c.Queryc.DefaultQuery 获取。

  • c.Query("firstname") 是从 HTTP GET 请求的查询参数中获取名为 “firstname” 的参数值。

    http://example.com/welcome?firstname=John&lastname=Doe

    • 查询参数通常在 URL 中以 ? 开始,每个参数以 & 分隔,
  • c.Queryc.DefaultQuery 都是用于从 HTTP GET 请求的查询参数中获取值的方法,

    • 但它们在处理不存在的参数时的行为不同。
      • c.Query("paramName") 会尝试获取名为 "paramName" 的查询参数的值。如果该参数不存在,它将返回空字符串。

      • c.DefaultQuery("paramName", "defaultValue") 也会尝试获取名为 "paramName" 的查询参数的值。但是,如果该参数不存在,它将返回提供的默认值 "defaultValue",而不是空字符串。

        r.GET("/welcome", func(c *gin.Context) {
            firstname := c.Query("firstname")
            lastname := c.DefaultQuery("lastname", "Guest")
            c.String(http.StatusOK, "Hello %s %s", firstname, lastname)
        })

3. 获取 POST 表单数据

POST 请求的表单数据可以通过 c.PostFormc.DefaultPostForm 获取。(区别同理,是否提供默认值)

r.POST("/form_post", func(c *gin.Context) {
    message := c.PostForm("message")
    nick := c.DefaultPostForm("nick", "anonymous")
    c.JSON(http.StatusOK, gin.H{
        "status":  "posted",
        "message": message,
        "nick":    nick,
    })
})

4. 获取 JSON数据

对于 JSON数据,可以使用 c.BindJSONc.ShouldBindJSONJSON数据绑定到结构体。

  • 默认选择c.ShouldBindJSON (更灵活)
type Login struct {
    User     string `json:"user" binding:"required"`
    Password string `json:"password" binding:"required"`
}

r.POST("/login", 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 != "admin" || json.Password != "admin" {
        c.JSON(http.StatusUnauthorized, gin.H{"status": "unauthorized"})
        return
    }
    c.JSON(http.StatusOK, gin.H{"status": "you are logged in"})
})

5. 获取 Header 信息

可以通过 c.GetHeader 获取请求头信息。

r.GET("/header", func(c *gin.Context) {
    ua := c.GetHeader("User-Agent")
    c.String(http.StatusOK, ua)
})

6. 获取文件上传

文件上传可以通过 c.FormFile 获取,并保存到服务器上。

r.POST("/upload", func(c *gin.Context) {
    file, _ := c.FormFile("file")
    c.SaveUploadedFile(file, "uploads/" + file.Filename)
    c.String(http.StatusOK, fmt.Sprintf("'%s' uploaded!", file.Filename))
})

file, _ := c.FormFile("file")

  • c.FormFile 方法用于从 POST 请求中获取上传的文件。"file" 是 HTML 表单中的 <input type="file" name="file"> 的字段名称。
  • 这行代码将上传的文件赋值给 file 变量。第二个返回值是可能的错误,但在这个例子中被忽略了(用 _ 表示)。

c.SaveUploadedFile(file, "uploads/" + file.Filename)

  • c.SaveUploadedFile 方法用于将上传的文件保存到服务器上的指定路径。
  • file 是从表单中获取的文件对象,"uploads/" + file.Filename 是文件保存的路径。file.Filename 是上传文件的原始文件名。
  • 在这个例子中,文件将被保存到 uploads 目录下,文件名保持不变。

:two: 返回响应给前端

1. 返回字符串

用于简单的文本或消息。

c.String(http.StatusOK, "Hello, World!")

2. 返回 JSON

用于返回结构化的 JSON 数据,通常用于 API 响应。

c.JSON(http.StatusOK, gin.H{
    "message": "Hello, World!",
    "status":  "success",
})

:three: 存取上下文变量

在 Go 的 Gin 框架中,c.GetInt64("uid") 是从 Gin 的上下文(*gin.Context)中获取 uid 的值。这个 uid 是一个从请求中提取或设置的值,通常是在处理 HTTP 请求时的中间件或处理函数中进行存储的。

如何存储到上下文中?

通常,uid 可能会通过以下几种方式存储到 Gin 上下文中:

  1. 中间件中存储:

    • 在请求处理链中的某个中间件函数中,uid 被提取出来(例如,从请求头、查询参数、Cookie 中等),然后使用 c.Set("uid", uid) 存储到上下文中。

    • 示例:

      func AuthMiddleware() gin.HandlerFunc {
          return func(c *gin.Context) {
              uid := extractUIDFromRequest(c) // 假设你有个函数来提取 uid
              c.Set("uid", uid)
              c.Next()
          }
      }
      • 另外,关于c.Next()
        • c.Next()被用在 JWT 中间件中。这个中间件首先检查请求的 Authorization 头来验证 JWT。
        • 如果验证成功,它会将用户 ID 设置到上下文中,然后调用 c.Next() 来启动后续的处理函数。
        • 如果验证失败,它会直接返回一个错误响应,不会调用 c.Next(),所以后续的处理函数不会被执行。
  2. 在处理函数中存储:

    • 有时 uid 可能会在请求处理函数中直接存储到上下文中,尤其是在处理特定的请求时,可能需要动态设置上下文的值。

    • 示例:

      func SomeHandler(c *gin.Context) {
          uid := getUIDFromSomewhere() // 从某处获取 uid
          c.Set("uid", uid)
          // 继续处理请求
      }

有效期是什么时候?

uid 的有效期是与当前请求的生命周期相同的。也就是说:

  • 请求生命周期:当一个 HTTP 请求到达时,一个新的 *gin.Context 实例会被创建并与请求相关联。所有在请求处理中存储在上下文中的数据(包括 uid)都只在这个请求的生命周期内有效。
  • 处理完成:一旦请求处理完成,*gin.Context 实例就会被销毁,存储在其中的数据也会丢失。下一个请求会创建一个新的 *gin.Context 实例,所以 uid 的值不会在不同请求之间保持。

:four:上下文处理

  1. context.Background():
    • 作用:它返回一个空的上下文(context),这个上下文永远不会被取消,也没有存储值,也没有设定任何截止时间。它通常作为其他上下文的基础上下文。
    • 使用场景:当你需要一个不需要取消或进一步控制的基础上下文时,可以使用它。通常在不需要取消或超时控制的顶级函数调用中使用。
  2. context.WithCancel(context.Background()):
    • 作用:这个函数返回一个从 context.Background() 派生出来的上下文,并返回一个 cancel 函数。你可以调用这个 cancel 函数来取消上下文。
    • 使用场景:当你需要能够取消上下文的功能时使用。例如,当你启动一个可能需要在某个时间点停止的 goroutine 时,可以将这个可取消的上下文传递给 goroutine,并在需要停止时调用 cancel 函数。

为什么需要使用上下文(Context)?

  • 取消操作:上下文用于管理并发操作的生命周期,特别是在涉及多个 goroutine 时,能够通过上下文传递取消信号来安全地停止这些操作。