kratos 的 http 路由必须在 .proto 文件中通过 option (google.api.http) 显式声明,编译期生成路由代码;需确保 proto 位置、语法、插件三者齐备,并在 http.server 中手动调用 registerxxxhttpserver 才生效。

proto 文件里写 option (google.api.http) 才算真正配置路由
Kratos 的 HTTP 路由不是靠 http.Server 的 HandleFunc 或类似 Gin 的 GET("/xxx") 动态注册,而是编译期从 .proto 文件里提取的。你改了 internal/server/http.go 但没动 api/xxx/v1/xxx.proto,路由就根本不会生成。
必须在 service 方法上加 option (google.api.http) 声明,例如:
rpc GetUser (GetUserRequest) returns (GetUserReply) {
option (google.api.http) = { get: "/v1/user/{id}" };
}
常见错误包括:
-
get:写成GET:(大小写敏感,只认小写) - 路径里用了
{id}却没在GetUserRequestmessage 里定义int64 id = 1; - 漏了
import "google/api/annotations.proto";,导致 protoc 不认识google.api.http - 路径写成
/user,但 Kratos 默认前缀是/v1,实际访问得是/v1/user,除非你显式删掉 proto 里的v1目录层级
make api 失败时,api/ 目录结构和插件缺一不可
make api 看似只是个命令,但它背后依赖三个硬性条件同时满足:目录位置、proto 语法、插件安装。任一缺失都会静默失败,只报 failed to generate,不提示具体哪错了。
必须确认:
-
.proto文件严格放在api/xxx/v1/下(不能是proto/、internal/proto或项目根目录) -
package声明必须匹配目录,如package api.helloworld.v1; - 装齐三款 protoc 插件:
protoc-gen-go、protoc-gen-go-grpc、protoc-gen-go-http/v2;少一个,v1.RegisterXXXHTTPServer就不会生成 -
syntax = "proto3";必须顶格写,前面不能有空行或缩进
检查是否成功:运行后看 api/xxx/v1/xxx_http.pb.go 是否存在,里面有没有 RegisterXXXHTTPServer 函数。
v1.RegisterXXXHTTPServer 必须手动调用,Kratos 不自动扫描
就算 proto 写对了、make api 成功了,如果没在 internal/server/http.go 里显式调用注册函数,服务起来后所有 HTTP 接口仍是 404。
典型注册写法:
h := http.NewServer(
http.Address(":8000"),
http.Middleware(...),
)
v1.RegisterDeviceHTTPServer(h, svc) // ← 这行不能少,svc 是你的 service 实例
注意点:
- 函数名中的
Device来自 proto 里service DeviceService的名字,大小写和拼写必须完全一致 -
svc类型必须实现v1.UnimplementedDeviceServiceServer接口,否则编译报错 - 如果你改过 proto 文件但没重新
make api,RegisterDeviceHTTPServer函数就不存在,Go 会直接编译失败
路径前缀和 method 映射由 proto 决定,别在 handler 层硬编码
有人试图在 service 层用 if r.URL.Path == "/v1/user" 做路由分发,这是反模式。Kratos 的设计是「契约先行」:proto 定义了哪些 path、method、参数绑定方式,生成代码就严格按这个执行。
比如这段 proto:
rpc CreateUser (CreateUserRequest) returns (CreateUserReply) {
option (google.api.http) = { post: "/v1/user" };
}
它意味着:
- 只响应
POST /v1/user,其他 method(如 GET)直接 405 - 请求体必须是 JSON 或 proto binary,且字段能映射到
CreateUserRequest的字段 - 没有额外中间件或逻辑介入的话,
/v1/user/123这种带路径参数的写法不会命中该接口
真正要支持 RESTful 风格的多级路径,得靠 proto 里更细的 option 控制,比如 post: "/v1/user/{parent}/child",并确保 request message 里有对应字段。
最常被忽略的一点:路由是否生效,和 main() 里 kratos.New() 能否启动成功无关。即使整个服务跑起来了,只要 RegisterXXXHTTPServer 没调、或 xxx_http.pb.go 没生成、或 proto 里没写 google.api.http,curl 就永远 404——它压根没挂到 HTTP server 上。











