微服务模块必须从main分离出可测试的handler层:将路由注册、中间件、启动逻辑移出main.go,使handler仅解析请求、调用service、写响应,service层无框架依赖,配置通过构造函数注入,健康检查与指标直连go运行时。

微服务模块必须从 main 分离出可测试的 handler 层
Go 微服务一旦把路由注册、中间件、启动逻辑全塞进 main.go,就很难做单元测试,也难以复用到其他服务或 CLI 工具中。核心是把业务逻辑和 HTTP 绑定解耦。
-
handler函数只负责解析请求、调用 service、写响应,不碰http.ResponseWriter以外的 net/http 类型(比如不直接调用http.Error) - service 层接收结构体参数、返回结构体或 error,完全无框架依赖
- 在
main.go中用http.HandleFunc或chi.Router等注册 handler,但 handler 实现放在独立包里(如internal/handler)
用 net/http 原生路由 + http.Handler 接口比过早引入 Gin/echo 更可控
多数内部微服务不需要 Gin 的反射式路由或复杂中间件栈,原生 http.ServeMux 或轻量第三方如 chi 足够,且更易调试、内存占用更低。
-
chi支持路径参数(/user/{id})和中间件组合,但底层仍是http.Handler,不会隐藏连接生命周期 - 避免在 handler 里用
context.WithTimeout包裹整个请求处理——超时应由反向代理(如 Envoy)或客户端控制,服务内超时容易掩盖真实瓶颈 - 若用
http.ServeMux,注意它不支持通配路径(如/api/*),需手动匹配前缀或改用http.StripPrefix
配置加载必须支持多环境且不硬编码默认值
开发、测试、生产环境的数据库地址、超时时间、重试次数差异极大,靠 if env == "prod" 判断会埋下维护雷。
- 用
viper读取 YAML/JSON 配置,但禁用自动搜索路径(viper.AddConfigPath),显式指定配置文件路径,避免本地残留 config.yaml 干扰 CI - 所有配置字段必须有明确类型和校验:比如
db.timeout是time.Duration,不是字符串;缺失时 panic 比静默 fallback 更安全 - 不要把配置结构体暴露给 handler 层——通过构造函数注入依赖,例如
NewUserService(cfg *DBConfig),而非全局变量var DB *sql.DB
健康检查与指标暴露要直连 Go 运行时,别绕路 Prometheus client
简单微服务的健康检查(/health)和基础指标(goroutines、allocs)不需要完整 Prometheus 生态,Go 自带的 expvar 和 runtime 包足够快且零依赖。
-
expvar.Publish("goroutines", expvar.Func(func() interface{} { return runtime.NumGoroutine() }))可直接被 Telegraf 或 curl 抓取 -
/health返回200 OK即可,除非依赖外部组件(如 DB),否则不要做深度探活——K8s 的 liveness probe 本身就有重试和超时机制 - 如果真要用 Prometheus,用
promhttp.Handler()暴露/metrics,但避免在 handler 里调用prometheus.NewCounterVec——指标注册应在 init 阶段完成
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











