net/http标准库够用,适用于5–10接口、qps≤2000、无复杂中间件的轻量项目;go 1.22+ servemux已支持路径参数,优势是零依赖、启动快、调试清晰,缺点是无自动参数绑定与上下文封装,典型误用是将db操作等业务逻辑直接塞入handlefunc。

Go 后端开发不需要框架也能跑通核心逻辑,但选错框架或用法不当,反而会拖慢迭代、掩盖并发问题、增加部署复杂度。
net/http 标准库够不够用?
够——前提是项目规模在 5–10 个接口、QPS 不超 2000、无复杂中间件链需求。Go 1.22+ 的 http.ServeMux 已支持路径参数(如 GET /users/{id}),无需额外依赖。
- 优点:零依赖、启动快、内存占用低、调试链路清晰(
HandlerFunc→ServeHTTP一目了然) - 缺点:不提供请求上下文封装(
context.Context需手动传)、无内置参数绑定/校验、错误处理需自行组织 - 典型误用:把所有逻辑塞进
http.HandleFunc匿名函数里,导致 handler 层直接操作数据库、拼 SQL、写日志,违反分层约束
Gin 和 Echo 哪个更适合快速交付?
选 Gin —— 它的 c.Param()、c.ShouldBindJSON()、c.AbortWithError() 这套 API 更贴近实际开发直觉,且文档示例可直接抄进项目跑通。
- Gin 的
gin.Context是http.ResponseWriter+*http.Request+map[string]interface{}的组合,方便透传数据;Echo 的echo.Context更轻但需要更多手动类型断言 - 两者都默认启用
Recovery中间件,但 Gin 的 panic 捕获堆栈更完整,Echo 在高并发下偶发 context cancel 错误未透出 - 注意
gin.Default()自带Logger和Recovery,上线前必须替换Logger为结构化日志(如zerolog),否则日志无法被 ELK 解析
路由怎么拆才不会后期重构?
按资源边界拆,不是按功能或团队拆。比如 /api/v1/users 下所有操作归到 user.go,而不是把 CreateUser 放 auth/、UpdateUser 放 profile/。
- 每个路由文件导出一个
SetupXXXRoutes(r *gin.RouterGroup)函数,由main.go统一注册,避免全局变量污染 - 路径参数必须校验:Gin 的
c.Param("id")返回 string,但业务层要立刻转成int64或uuid.UUID,否则空字符串或非法格式会在 DB 层才暴露 - 禁止在路由定义里写业务逻辑:下面这种写法是反模式:
r.GET("/users/:id", func(c *gin.Context) { /* DB 查询 + JSON 序列化 */ })
中间件里最容易漏掉的 context 传递
自定义中间件必须调用 next.ServeHTTP(w, r),且不能修改 r.Context() 以外的任何字段。常见坑是:在中间件里解析 JWT 后只存到 c.Set("user_id", id),但 service 层却直接从 c.Request.Context().Value() 取值,导致取不到。
- 正确做法:用
context.WithValue(r.Context(), key, value)构造新 context,并通过r.WithContext(newCtx)替换请求上下文 - key 必须是私有类型(如
type userIDKey struct{}),不能用 string,否则不同中间件 key 冲突 - 日志中间件务必在
next.ServeHTTP前后记录耗时,但不要在 defer 里读w.Header()—— 此时 header 可能已被其他中间件修改,应读w.(ResponseWriter).Status()
真正卡住多数人的不是语法或框架 API,而是没想清楚“这个请求的生命周期里,哪些数据必须跨 handler/service/repository 流动,又该以什么方式携带”。context 传参、error 包装、response 封装这三件事,比选哪个框架重要十倍。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











