前言
继上一篇我们学习了如何通过 GET 接口接收 URL 参数,今天我们继续来写一个 POST 接口,学习如何在 Gin 中接收 JSON 请求数据,并返回响应。
Gin 中常见的参数接收方式
在我们使用结构体绑定之前,先快速过一下 Gin 中的几种参数接收方式
1.路径参数(Path 参数)c.Param("xxx")
适用于 /user/:id
这种 URL:
go
r.GET("/user/:id", func(c *gin.Context) {
id := c.Param("id")
c.JSON(200, gin.H{"user_id": id})
})
访问 /user/123
,就会返回:
json
{"user_id": "123"}
2.查询参数(Query 参数)c.Query()
或 c.DefaultQuery()
适用于 /hello?name=Gin
:
go
r.GET("/hello", func(c *gin.Context) {
name := c.DefaultQuery("name", "World") // 如果没传就默认 World
c.JSON(200, gin.H{"message": "Hello " + name})
})
访问 /hello?name=Gin
→ {"message": "Hello Gin"}
3.表单参数(Post 表单)c.PostForm()
适用于表单格式请求(如 Content-Type: application/x-www-form-urlencoded
):
go
r.POST("/login", func(c *gin.Context) {
username := c.PostForm("username")
password := c.PostForm("password")
...
})
总的来说就是这样的:
类型 | 方法 | 示例说明 |
---|---|---|
路径参数 | c.Param("id") |
/user/:id |
查询参数 | c.Query("name") |
/hello?name=Gin |
表单参数 | c.PostForm("key") |
application/x-www-form-urlencoded |
JSON 参数 | c.ShouldBindJSON() |
本篇重点(结构体绑定) |
接下来:结构体绑定 JSON 参数
介绍完基本的参数获取方法,我们回到本篇重点 ------
使用结构体绑定 JSON 请求体(更适用于 RESTful 接口)
在实际项目中,一个接口往往会接收多个字段(如 name、age、email、password 等),如果每个字段都用 c.PostForm()
或 c.Query()
去取,不仅代码冗长,还容易遗漏或拼错字段名。所以我们可以采用结构体绑定的方式来统一管理接收参数。
场景模拟
我们要实现一个简单的注册接口:
- 请求方式:
POST /register
- 接收参数:
name
和age
(JSON 格式) - 返回内容:欢迎语和年龄信息
项目结构准备
我们在原项目结构的基础上新增了 user.go
控制器,并修改路由:
go
gin-learn-notes/
├── controller/
│ └── user.go ✅ 新增
├── router/
│ └── router.go ✅ 修改
├── main.go
第一步:创建 controller/user.go
go
// controller/user.go
package controller
import (
"github.com/gin-gonic/gin"
"net/http"
)
// 接收结构体
type RegisterRequest struct {
Name string `json:"name"`
Age int `json:"age"`
}
// POST /register
func Register(c *gin.Context) {
var req RegisterRequest
// 自动解析 JSON 到结构体
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, gin.H{
"error": "参数错误:" + err.Error(),
})
return
}
// 返回欢迎消息
c.JSON(http.StatusOK, gin.H{
"message": "欢迎 " + req.Name,
"age": req.Age,
})
}
这里补充解释一下上面的结构体标签 json:"name"
是做什么的?
go
type RegisterRequest struct {
Name string `json:"name"`
Age int `json:"age"`
}
-
这里的
json:"name"
表示:当我们接收一个 JSON 请求时,这个字段会绑定 JSON 中名为name
的字段值 -
如果没有写这个标签,默认会匹配结构体字段名(区分大小写),例如
Name
对应Name
(首字母大写),可能就会接收不到数据
那 ShouldBindJSON()
又是干嘛的呢?
在控制器中我们写了这句:
go
err := c.ShouldBindJSON(&req)
-
ShouldBindJSON()
是 Gin 提供的函数,用于把请求体中的 JSON 数据自动解析并填充到结构体里 -
它会根据结构体中的
json:"xxx"
标签去找对应的字段,如果格式不对(例如传了"age": "abc"
),就会自动报错
简而言之:
json:"xxx"
定义了字段和 JSON 的映射关系
ShouldBindJSON()
会自动解析、赋值并校验类型(基础校验)
这一对组合是 Gin 接收 POST 请求中 JSON 数据的核心,后面我们还可以在结构体上加上 binding:"required"
进行更强的参数校验。
第二步:注册 POST 路由
打开并修改 router/router.go
,添加 /register
接口注册:
go
package router
import (
"github.com/gin-gonic/gin"
"gin-learn-notes/controller"
)
func InitRouter() *gin.Engine {
r := gin.Default()
r.GET("/ping", controller.Ping)
r.GET("/hello", controller.HelloHandler)
// 👇 新增 POST 路由
r.POST("/register", controller.Register)
return r
}
测试 POST 接口
启动项目:
bash
go run main.go
使用 Postman、curl 或 REST Client 工具测试:
请求:
http
POST /register HTTP/1.1
Content-Type: application/json
{
"name": "Gin",
"age": 25
}
响应:
json
{
"message": "欢迎 Gin",
"age": 25
}
补充测试:发送非法 JSON,触发自动校验
Gin 使用 ShouldBindJSON
时,会自动根据结构体字段类型进行基本的类型校验。
比如我们之前定义的结构体中,age
是 int
类型:
go
type RegisterRequest struct {
Name string `json:"name"`
Age int `json:"age"`
}
现在我们发送一份非法的请求,把 age 写成字符串,看看会发生什么:
错误请求:
json
{
"name": "Gin",
"age": "twenty"
}
接口响应:
json
{
"error": "参数错误:json: cannot unmarshal string into Go struct field RegisterRequest.age of type int"
}
说明:
- Gin 在解析 JSON 时自动检测类型不匹配,并返回错误信息
- 参数校验机制已经在默认状态下生效,即使我们没显式加验证规则
现在我们的项目结构像这样:
go
gin-learn-notes/
├── controller/
│ └── hello.go
| └── index.go
| └── user.go
├── router/
│ └── router.go
├── main.go
├── go.mod
最后
在本篇中,我们主要完成了以下内容:
- 创建了
/register
接口,使用 POST 方法接收 JSON 请求体 - 编写了
RegisterRequest
结构体,用于参数绑定 - 学习了
ShouldBindJSON()
方法的用法 - 实现了 JSON 参数解析、类型校验与响应逻辑
- 补充测试了非法参数格式,验证了绑定失败自动报错机制
本篇对应代码提交记录
commit: ba9363e8f9319aae0d7bc6cdc3446197cc98d443
👉 GitHub 源码地址:github.com/luokakale-k...
下一篇我们将继续深入学习:如何集成 GORM + MySQL,实现注册用户入库。