Gin 框架学习实录 · 第2篇:接收 JSON 参数,编写 POST 接口

前言

继上一篇我们学习了如何通过 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
  • 接收参数:nameage(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 时,会自动根据结构体字段类型进行基本的类型校验。

比如我们之前定义的结构体中,ageint 类型:

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,实现注册用户入库。

相关推荐
我是前端小学生1 小时前
面试官:在go语言中,主协程如何等待其余协程完毕再操作?
go
关山月2 小时前
学习Go语言:循环和条件语句
go
我是前端小学生2 小时前
面试官:在go语言中,使用for select时,如果通道已经关闭会怎么样?如果只有一个case呢?
go
我是前端小学生2 小时前
面试官:在go语言中,在 for range 循环中对切片(slice)使用append操作,会造成无限循环吗?
go
三块钱07949 小时前
【原创】通过S3接口将海量文件索引导入elasticsearch
大数据·elasticsearch·搜索引擎·go
一个热爱生活的普通人19 小时前
JWT认证:在gin服务中构建安全的API接口
后端·go·gin
洛卡卡了21 小时前
Gin 框架学习实录 · 第4篇:参数校验、结构体拆分与控制器职责解耦
go
洛卡卡了21 小时前
Gin 框架学习实录 · 第3篇:集成 GORM + MySQL,实现注册用户入库
go
Pandaconda1 天前
【新人系列】Golang 入门(七):闭包详解
开发语言·经验分享·笔记·后端·golang·go·闭包
forever231 天前
kubebuilder创建k8s operator项目(下)
go