grpc-gateway需三步:先用protoc生成grpc stub(--go_out和--go-grpc_out),再单独运行gateway命令(显式指定third_party/googleapis路径),最后在listenandserve前调用registerxxxhandlerfromendpoint注册handler。

不能“一键”,但三步走对、两处不漏,HTTP 接口就能跑起来。
protoc 命令必须分两次执行,不能合并
很多人想用一条 protoc 命令同时生成 .pb.go、_grpc.pb.go 和 .pb.gw.go,结果要么报错 google/api/annotations.proto: File not found,要么生成的 .pb.gw.go 是空文件。
根本原因在于:插件职责不同——--go_out 和 --go-grpc_out 负责生成数据结构和 gRPC 接口;--grpc-gateway_out 只负责读取已有定义,生成反向代理逻辑,它不参与 protobuf 解析。
统一LLM网关 - 一个API对接70+AI模型,使用单一API密钥即可调用GPT、Claude、Gemini、Qwen、Deepseek、Grok等主流模型。
- 先运行 gRPC 生成命令(确保
.pb.go和_grpc.pb.go存在):protoc -I . -I $GOPATH/pkg/mod/github.com/grpc-ecosystem/grpc-gateway@v2.15.2/third_party/googleapis/ --go_out=. --go-grpc_out=. sum.proto - 再单独运行 gateway 命令:
protoc -I . -I $GOPATH/pkg/mod/github.com/grpc-ecosystem/grpc-gateway@v2.15.2/third_party/googleapis/ --grpc-gateway_out=. --grpc-gateway_opt logtostderr=true sum.proto - 如果用
buf,buf.gen.yaml中必须把plugin: grpc和plugin: grpc-gateway分开配置,不能塞进同一个plugins块里
google.api.http 注解写错一个字符,HTTP 就 404
这个注解不是装饰,是路由源。它直接决定 HTTP 方法、路径、参数绑定方式,且大小写、引号、字段名都必须严格匹配 Protobuf message 定义。
-
post: "/v1/users"表示整个请求体映射到入参 message,此时body: "*"是必需的;漏写会返回400 Bad Request,不是404 -
get: "/v1/users/{id}"要求 message 中存在字段string id = 1;;若字段名是user_id却写成{id},gateway 解析失败,直接404 - 路径中带 query 参数(如
get: "/v1/users?status={status}")时,status字段必须是 message 的一级字段,嵌套结构(如UserFilter.status)不支持自动展开 - 避免换行缩进写法:
option (google.api.http) = { post: "/v1/foo" };这种格式在某些旧版protoc下会被静默忽略
RegisterXXXHandlerFromEndpoint 必须在 ListenAndServe 前调用
生成的 .pb.gw.go 文件里会提供类似 RegisterSumHandlerFromEndpoint 的函数,它负责把反向代理 handler 挂载到 http.ServeMux 上。这个注册动作必须发生在 http.ListenAndServe 或 http.Server.Serve 之前,否则请求进来时 mux 还是空的。
- 常见错误写法:先
http.ListenAndServe(":8080", mux),再调用RegisterSumHandlerFromEndpoint - 正确顺序:
① 创建http.ServeMux
② 调用RegisterSumHandlerFromEndpoint(mux, ...)
③ 启动http.Server并传入该 mux - 注意 endpoint 参数要指向正在运行的 gRPC 服务地址(如
"localhost:8080"),不是":8080"—— 后者是监听地址,不是可连接的 endpoint
最容易被忽略的是 third_party/googleapis 路径的显式指定,以及 body: "*" 这类绑定规则和 message 字段的严格一致性——它们不出现在编译错误里,只在运行时用 400/404 静静惩罚你。










