Web

Gin 基础用法

Gin 是一个基于 Go net/http 的 Web 框架,常用于创建 HTTP API。本文只介绍搭建简单服务时最常用的功能。

安装 Gin

先创建 Go 模块并安装 Gin:

bash
go mod init example
go get github.com/gin-gonic/gin

创建第一个服务

下面的程序创建了一个 Gin Engine,并注册了一个返回 JSON 的路由:

go
package main

import (
	"net/http"

	"github.com/gin-gonic/gin"
)

func main() {
	r := gin.Default()

	r.GET("/hello", func(ctx *gin.Context) {
		ctx.JSON(http.StatusOK, gin.H{
			"message": "hello, Gin",
		})
	})

	r.Run(":8080")
}

运行程序后,访问 http://localhost:8080/hello,会得到:

json
{
  "message": "hello, Gin"
}

gin.Default() 会创建路由引擎,并自动添加日志和异常恢复中间件。Run() 默认启动 HTTP 服务。

注册路由

Gin 使用与 HTTP 方法同名的方法注册路由:

go
r.GET("/items", listItems)
r.POST("/items", createItem)
r.PUT("/items/:id", updateItem)
r.DELETE("/items/:id", deleteItem)

每个处理函数都接收一个 *gin.Context

go
func listItems(ctx *gin.Context) {
	ctx.JSON(http.StatusOK, gin.H{
		"items": []string{"book", "pen"},
	})
}

gin.H 构造 JSON 响应

gin.H 是 Gin 提供的 map 类型,底层与 map[string]any 等价,用来快速构造 JSON 响应。它可以存放字符串、数字、切片,甚至嵌套的 gin.H

go
ctx.JSON(http.StatusOK, gin.H{
	"id":     1,
	"name":   "book",
	"tags":   []string{"go", "gin"},
	"author": gin.H{
		"name": "Alice",
	},
})

返回的 JSON 是:

json
{
  "id": 1,
  "name": "book",
  "tags": ["go", "gin"],
  "author": {
    "name": "Alice"
  }
}

gin.H 的 key 必须是字符串,JSON 中的字段名会按照 key 原样输出。

读取请求参数

路径参数

路由中的 :id 表示路径参数,可以使用 ctx.Param() 读取:

go
r.GET("/items/:id", func(ctx *gin.Context) {
	id := ctx.Param("id")
	ctx.JSON(http.StatusOK, gin.H{"id": id})
})

访问 /items/1 时,id 的值是 "1"

查询参数

使用 ctx.Query() 读取 URL 查询参数:

go
r.GET("/search", func(ctx *gin.Context) {
	keyword := ctx.Query("keyword")
	ctx.JSON(http.StatusOK, gin.H{"keyword": keyword})
})

访问 /search?keyword=go 时,keyword 的值是 "go"

绑定 JSON 请求体

可以将 JSON 请求体绑定到结构体,并使用 binding 标签完成基础校验:

go
type CreateItemRequest struct {
	Name string `json:"name" binding:"required"`
}

func createItem(ctx *gin.Context) {
	var request CreateItemRequest
	if err := ctx.ShouldBindJSON(&request); err != nil {
		ctx.JSON(http.StatusBadRequest, gin.H{
			"error": "name is required",
		})
		return
	}

	ctx.JSON(http.StatusCreated, gin.H{
		"name": request.Name,
	})
}

请求时需要设置 Content-Type: application/json

bash
curl -X POST http://localhost:8080/items \
  -H 'Content-Type: application/json' \
  -d '{"name":"book"}'

ShouldBindJSON() 只返回绑定错误,不会自动生成响应,因此可以自行决定状态码和错误内容。

使用路由组

多个接口拥有相同前缀时,可以使用 Group()

go
api := r.Group("/api")
{
	api.GET("/items", listItems)
	api.POST("/items", createItem)
}

上面的路由地址分别是 GET /api/itemsPOST /api/items。大括号只用于整理代码,不影响路由行为。

添加中间件

中间件可以在处理请求前后执行公共逻辑。下面的示例为响应添加一个固定的响应头:

go
func AddResponseHeader() gin.HandlerFunc {
	return func(ctx *gin.Context) {
		ctx.Header("X-App", "gin-example")
		ctx.Next()
	}
}

r.Use(AddResponseHeader())

r.Use() 注册全局中间件,ctx.Next() 继续执行后续中间件和最终的路由处理函数。

常用响应方法

Gin 提供了多种响应方法:

go
ctx.JSON(http.StatusOK, gin.H{"message": "ok"})
ctx.String(http.StatusOK, "ok")
ctx.Status(http.StatusNoContent)

处理函数写入响应后,如果后面还有代码,应及时 return,避免重复写入响应。

总结

Gin 的基础使用流程是:创建 Engine、注册路由、通过 gin.Context 读取请求并写入响应。掌握路径参数、查询参数、JSON 绑定、路由组和简单中间件后,就可以开始编写基础 HTTP API。