grpc-gateway 不是自动路由的魔法中间件,所有路由绑定在 protoc 生成阶段固化,必须显式调用 registerxxxhandlerfromendpoint 才能生效;proto 中 google.api.http 注解仅用于代码生成,不运行时生效。

不能“自动路由”——grpc-gateway 不是魔法中间件,它不监听路径、不动态注册、不扫描 proto 注解运行时生效。所有路由绑定都在 protoc 生成阶段固化,必须显式调用 RegisterXXXHandlerFromEndpoint 才能生效。
proto 中的 google.api.http 注解只用于代码生成
你写 get: "/v1/users/{id}" 或 post: "/v1/users" body: "*",这些不会让程序启动后“自动挂载路由”。它们仅被 protoc-gen-grpc-gateway 插件读取,用来生成 service.pb.gw.go 里的 runtime.NewServeMux() 绑定逻辑。
- 必须在
.proto文件中import "google/api/annotations.proto"和import "google/api/http.proto",否则插件静默忽略注解 -
body: "*"表示整个 JSON body 解析进 message;若写body: "user.name",gateway 会按字段路径提取,但字段不存在时直接丢弃,不报错 - 路径参数(如
{id})和 query 参数(如?page=1)都必须在 request message 中定义对应字段,否则 gateway 不解析、不传入 gRPC 方法
RegisterXXXHandlerFromEndpoint 必须手动调用且不能塞进 Gin/Echo
生成的 service.pb.gw.go 里有类似 RegisterGreeterHandlerFromEndpoint 的函数,它把 gRPC 方法注册到 runtime.ServeMux —— 这是一个独立的 HTTP handler,不是中间件。
在 macOS 上通过 LaunchAgent 安装、更新、运行和移除 OpenClaw Gateway Monitor + Gateway Watchdog。适用于用户请求一键部署监控的场景。
- 不能写成
r.POST("/xxx", mux.ServeHTTP):Gin/Echo 会丢失 method/path 匹配,所有请求 fallback 到 404 - 必须用
http.ListenAndServe(":8080", mux)直接启动,或封装为http.Server{Handler: mux} -
ctx参数不能是已 cancel 的 context(比如context.WithTimeout创建后已超时),否则注册失败且无任何提示 -
endpoint必须指向正在运行的 gRPC server 地址(如"localhost:9090"),不能是 DNS 未解析、端口未监听或防火墙拦截的地址
共用端口需靠 h2c + fallback,不能两个 ListenAndServe
想让 8080 端口同时响应 REST 和 gRPC 请求,常见错误是起两个 server 或让 gRPC server 直接 Serve(lis) —— 这会导致 socket 抢占、连接中断、随机 503。
- 正确做法:用
golang.org/x/net/http2/h2c.NewHandler包裹 gRPC server,作为http.ServeMux的 fallback handler - 主 handler 是
runtime.ServeMux,未匹配的请求(比如 gRPC over HTTP/1.1)才交给 fallback 处理 - 不能复用 listener,必须由同一个
http.Server统一接管连接
最易被忽略的是:gateway 与 gRPC server 的生命周期必须对齐 —— endpoint 断开时,gateway 不会自动重连,也不会报错;它只会持续返回 503,直到你重启或加健康检查兜底。










