Go mod 好菜系列 - 0x01 Gin 真的是第一口常见菜

详细聊 gin 是什么、适合干什么、路由/中间件/参数绑定/响应处理怎么写,以及为什么它在 Go Web 项目里这么常见。

如果你在 Go 里开始写 Web 服务,大概率很快就会碰到 gin。它的存在感高到一种程度:很多人甚至不是先学标准库里的 net/http,而是先学 gin。这个顺序未必最理想,但它确实说明了 gin 的工程地位。

gin 是干嘛的

一句话说,就是一个 Web 框架。更准确一点说,它是在标准库 net/http 之上,给你补了一整套更顺手的接口开发工具:

  • 路由组织
  • 中间件
  • 请求参数读取
  • JSON 响应
  • 参数绑定和校验衔接

如果你只用标准库,很多事情也不是做不到,只是你会写得更原始一些,重复代码也会更多一些。

为什么 gin 常见

因为它在很多团队里处在一个很舒服的位置:

  • 比纯标准库省事
  • 比一些更重的框架轻
  • 文档和资料多
  • 大家都认识,接手成本低

它不一定是唯一选择,但它经常是“大家都能接受、也比较容易上手”的那一个。

最小可用示例

package main

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

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

    r.GET("/ping", func(c *gin.Context) {
        c.JSON(200, gin.H{
            "message": "pong",
        })
    })

    r.Run(":8080")
}

这里有几个点一眼先记住:

  • gin.Default() 会默认带上日志和 recover 中间件
  • r.GET 注册路由
  • c.JSON 直接返回 JSON
  • r.Run 启动服务

也就是说,很多你在标准库里要自己拼的东西,gin 已经给你包装得比较顺手了。

路由写起来为什么更舒服

标准库当然也能注册路由,但 gin 在路由层做得更直观,尤其是分组。

api := r.Group("/api")
{
    api.GET("/users", listUsers)
    api.GET("/users/:id", getUser)
    api.POST("/users", createUser)
}

这个写法在接口一多的时候很有用。路径前缀、鉴权中间件、版本区分,都更容易挂在 group 上统一处理。

参数获取和绑定

这是 gin 特别讨喜的一点。它把参数来源拆得很清楚:

  • 路径参数:c.Param()
  • 查询参数:c.Query()
  • 表单参数:c.PostForm()
  • JSON 绑定:c.ShouldBindJSON()
func getUser(c *gin.Context) {
    id := c.Param("id")
    keyword := c.Query("keyword")
    c.JSON(200, gin.H{
        "id":      id,
        "keyword": keyword,
    })
}

再看 JSON 绑定:

type CreateUserReq struct {
    Name string `json:"name" binding:"required"`
    Age  int    `json:"age"`
}

func createUser(c *gin.Context) {
    var req CreateUserReq
    if err := c.ShouldBindJSON(&req); err != nil {
        c.JSON(400, gin.H{"error": err.Error()})
        return
    }

    c.JSON(200, gin.H{"name": req.Name})
}

这也是为什么 gin 特别适合写 API:它已经把请求绑定这类脏活累活做得很顺了。

中间件为什么是 gin 的重头戏

gin 项目里,中间件的存在感非常高。日志、鉴权、限流、panic 兜底、统一 request id,很多事情都会落到这里。

func AuthMiddleware() gin.HandlerFunc {
    return func(c *gin.Context) {
        token := c.GetHeader("Authorization")
        if token == "" {
            c.AbortWithStatusJSON(401, gin.H{"error": "unauthorized"})
            return
        }
        c.Next()
    }
}
api := r.Group("/api")
api.Use(AuthMiddleware())

这套写法很适合工程里做横切逻辑。别把这些检查全塞到每个 handler 里,不然很快就会变成复制粘贴型开发。

gin 能帮你省什么事

  • 少写很多请求解析和响应包装的样板代码
  • 接口组织更清晰
  • 中间件扩展方便
  • 和 validator、JWT、日志这些工具库衔接比较顺

也就是说,gin 不是为了“更炫”,而是为了让接口开发更像一条流水线。

gin 不是万能的地方

也别把 gin 神化。它不是说用了以后项目结构就自动优雅了。很多 gin 项目也一样会烂,只是烂得更快。

常见坏味道包括:

  • 所有业务都写在 handler 里
  • 路由文件越来越大
  • 绑定、鉴权、数据库、响应全糊在一起
  • 把 gin.Context 一路传到 service 和 repository 里当万能口袋

gin 只是入口层框架,不是架构本身。你还是得自己把层次划清。

适合放在项目哪一层

最健康的理解是:gin 属于 接口入口层。它负责:

  • 收请求
  • 做初步绑定和校验
  • 调用 service
  • 把结果编码成 HTTP 响应

数据库操作、核心业务逻辑、复杂规则判断,别因为 gin 好用,就顺手全写在 c 这个变量边上。

小结

gin 之所以常见,不是因为它神,而是因为它刚好把 Go Web 里那层最烦人的样板劳动解决掉了:

  • 它让路由、中间件、参数绑定和 JSON 响应更顺手
  • 它特别适合接口型服务
  • 它不负责替你设计分层,只负责让入口层更舒服
  • 会用 gin 很重要,但别把整个项目都写成 gin 脚本

下一篇我们聊 gorm。gin 解决的是入口层,那 gorm 解决的,就是另一块特别高频又特别容易写烦的地方:数据库。

Read more

Harness Engineering:从驾驭模型到构建 AI 工厂

Harness Engineering:从驾驭模型到构建 AI 工厂

2026 年,AI 编程工具的竞争焦点发生了根本性转变:决定 AI 助手好不好用的,不再是模型本身,而是包裹在模型外面的那层"Harness"。同一个模型,在不同的 Harness 下,性能差距可以达到 78% vs 42%。 这篇文章将带你深入了解 Harness Engineering——这个正在重新定义 AI 工程实践的新兴领域。 一、什么是 Harness Engineering? Harness 的字面意思是"马具/缰绳"——用来驾驭一匹强壮但不受控的马。在 AI 语境下,Harness 就是 LLM 之外的一切:工具定义、记忆系统、权限模型、反馈循环、文档规范、多

By Fuyu Jia

Claude Code CLI + Ralph:让 AI 自动完成大型编程任务的终极方案

TL;DR 当你的编程任务大到一个 AI 对话窗口装不下时,Ralph 会帮你把任务拆成小块,让 Claude Code CLI 一个接一个地自动完成——每轮都用全新的上下文窗口,不会越写越糊涂。 一、什么是 Ralph? Ralph 是一个开源项目(GitHub 16k+ Stars),基于 Geoffrey Huntley 提出的 "Ralph Pattern" 构建。它的核心理念很简单: 不要让 AI 在一个漫长的会话里做完所有事情,而是把大任务拆成小故事,每个故事用一个全新的 AI 实例来完成。 这解决了 AI 编程中最常见的痛点——上下文窗口耗尽。当对话越来越长,AI 的输出质量会明显下降。Ralph 通过「每轮一个新实例」的方式,

By Fuyu Jia