go-kit 是约定优先的分层架构范式,必须严格遵循 service→endpoint→transport 三层结构:service 接口需定义 context.context 为首参、(t, error) 返回值;params 独立建模以统一双协议;endpoint 必须共用以保障中间件一致;router 注册顺序不可颠倒。

go-kit 不是“引入一个库”就能开跑的框架,它是一套约定优先的分层架构范式。直接 go get github.com/go-kit/kit 后写个 main() 是没法跑通完整服务的——你会卡在 Transport 解码失败、Endpoint 无法调用 Service、Model 层缺失导致协议不兼容等地方。
关键判断:工程结构比代码更早决定成败。Kit 的三层(Service → Endpoint → Transport)必须从目录和接口定义开始对齐,否则后续所有 HTTP/gRPC 双协议支持、中间件注入、错误统一处理都会断裂。
service 层必须先定义 interface,且方法签名带 context.Context
这是 Kit 的硬约束,不是可选习惯。Service 接口是整个项目的契约起点,所有上层(Endpoint/Transport)都依赖它。
-
context.Context必须作为第一个参数,Kit 的中间件(如超时、日志)靠它透传元数据 - 返回值必须是
(T, error)形式,Kit 的endpoint.Endpoint会按此约定解包 - 不要在 Service 方法里做协议相关操作(比如 JSON 序列化、HTTP 状态码设置),那是 Transport 层的事
示例:
type ArticleService interface {
Create(ctx context.Context, title string, content string) (int64, error)
GetByID(ctx context.Context, id int64) (Article, error)
}
<p>type articleService struct{ repo ArticleRepo }</p><p>func (s *articleService) Create(ctx context.Context, title, content string) (int64, error) {
return s.repo.Save(ctx, title, content) // 业务逻辑只管存,不管怎么传
}</p>
params 目录要独立建模,别和 transport 或 pb 混用
Kit 要求 HTTP 和 gRPC 请求最终都转成同一套领域模型(即 params),否则双协议无法共享 Service 实现。很多团队把 pb.ArticleRequest 直接塞进 Endpoint,结果 HTTP 请求 decode 失败或字段丢失。
- 在
params/article.go定义纯 Go 结构体,带 JSON tag 和 protobuf tag 两套注解 - HTTP Transport 的
decodeRequest函数负责把json.RawMessage转成params.CreateRequest - gRPC Transport 的
DecodeRequestFunc负责把*pb.CreateRequest转成params.CreateRequest - Service 层只认
params.Xxx,不碰任何pb.Xxx或http.Request
常见错误:HTTP 请求 body 是 {"title":"a","content":"b"},但 decode 函数试图直接赋值给 pb.CreateRequest,panic 报错 cannot assign *pb.CreateRequest to params.CreateRequest。
transport/http 和 transport/grpc 必须共用同一组 endpoint.Endpoint
Kit 的核心设计意图就在这里:Endpoint 是协议无关的函数类型 func(context.Context, interface{}) (interface{}, error)。HTTP 和 gRPC Server 都应调用同一个 createEndpoint,而不是各自实现一套。
- 在
endpoint/article.go中,用makeCreateEndpoint(svc ArticleService)构造闭包,返回endpoint.Endpoint - HTTP Server 用
httptransport.NewServer(createEndpoint, decodeHTTP, encodeHTTP) - gRPC Server 用
grpctransport.NewServer(createEndpoint, decodeGRPC, encodeGRPC) - 如果为 HTTP 写了
createHTTPHandler()、为 gRPC 写了CreateGRPCMethod(),说明你已经绕开了 Kit 的抽象,后续加熔断/限流会重复两套逻辑
性能影响:共用 Endpoint 意味着中间件(如 ratelimit.NewTokenBucketLimiter)只需 wrap 一次,避免在 HTTP/gRPC 两层各套一层限流器造成 double-throttling。
router/http 和 router/grpc 的注册顺序不能颠倒
Kit 本身不提供 Router,但实际项目中常搭配 gorilla/mux 或 gin 做 HTTP 路由、grpc.ServeMux 做 gRPC 注册。顺序错会导致服务启动时 panic 或路由静默失效。
- HTTP Router 必须在
httptransport.NewServer返回的http.Handler上注册,不是直接注册原始 handler 函数 - gRPC Router 必须用
grpc.NewServer()实例调用RegisterXXXServer(),不能漏掉pb.RegisterArticleServer(srv, service) - 常见坑:把
httptransport.NewServer返回的 handler 当作普通函数传给r.HandleFunc,结果 404;或忘记在 gRPC server 上注册 pb 生成的服务,导致客户端报UNIMPLEMENTED
最容易被忽略的一点:Kit 的 Transport 层不自动处理 CORS、gzip、HTTPS 重定向——这些仍需你在 Router 层手动加 middleware,别指望 httptransport 包含它们。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











