HTTP 404但服务启动成功,主因是路由未注册:漏调v1.RegisterXXXHTTPServer、api/v1/xxx_http.pb.go未生成(make api失败)、或proto中HTTP路径前缀(如/v1)与访问路径不匹配。

kratos.New() 启动不 panic,不代表 HTTP 服务能响应请求——常见原因是 http.Server 实例没注册路由、RegisterXXXHTTPServer 没调用、或路径前缀不匹配。
HTTP 路由注册失败:404 但服务已启动
服务日志显示 start http server at [::]:8000,但 curl http://localhost:8000/v1/say/hello 返回 404,问题几乎总出在三处:
-
internal/server/http.go中漏掉了v1.RegisterGreeterHTTPServer(或你自己的RegisterDeviceHTTPServer)调用 -
api/v1/greeter_http.pb.go文件未生成(make api失败或被跳过),导致注册函数根本不存在 - proto 中定义的 HTTP 路径带前缀,比如
get: "/v1/hi/{name}",但你访问的是/hi/1;Kratos 不自动裁剪/v1,必须按 proto 定义的完整路径访问
中间件里取不到 ctx.Value() 的值
Kratos 的 HTTP 中间件默认接收的是标准 *http.Request,其 Context() 和你在 handler 里用 transport.HTTPRequestContext(r) 拿到的不是同一个上下文。你塞进 context.WithValue() 的数据不会自动透传。
- 必须显式把值注入 request context:
r = r.WithContext(context.WithValue(r.Context(), key, val)),再调next.ServeHTTP(w, r) -
transport.HTTPContext()返回的是空 context,不能用来存业务数据;只有transport.HTTPRequestContext(r)才包装了 request 信息,但也需手动注入 - 如果用
http.Middleware()注册中间件(如logging.Server(logger)),它内部已处理好 context 透传,但自定义中间件必须自己做
service.Register() 报 rpc error: code = Unavailable
这个错误和远程服务无关,纯粹是本进程内 gRPC server 缺失或未就绪。
-
service.Register()是向本进程的grpc.Server实例注册 service,不是发网络请求——它失败,说明grpc.NewServer()没调,或返回了nil(比如 Consul 连不上时consul.New()可能只返回 error,实例为 nil) - 确认
grpc.Server实例已加入kratos.New(kratos.Server(httpSrv, grpcSrv))参数列表;漏传grpcSrv就等于没启 gRPC - 如果项目纯 HTTP,完全不用
service.Register();HTTP 路由与 gRPC 注册解耦,删掉这行代码反而更干净
proto 更新后 HTTP 接口不生效
改了 greeter.proto 加了新接口,make api 也跑过了,但新路由就是 404。本质是生成链断裂:
-
go_package必须严格匹配:proto 里写option go_package = "api/helloworld/v1;helloworldv1",生成文件的package helloworldv1就得一致,否则 import 错乱 - 生成命令必须带
paths=source_relative,否则greeter_http.pb.go会生成到错目录,RegisterGreeterHTTPServer函数找不到 -
make api不会自动清理旧文件,建议先rm api/**/*.pb.go再重跑,避免残留旧代码干扰
最常被忽略的一点:Kratos 的 HTTP 路由注册不是靠反射扫描,而是靠显式调用生成的 RegisterXXXHTTPServer 函数——它像一把锁,没调,再正确的 proto 和中间件也打不开路由。


















