grpc-gateway是基于protobuf定义自动生成http/json反向代理逻辑的工具,它在进程内将rest请求解析为grpc结构体并调用本地grpc方法,再将响应序列化为json返回,不跨服务转发;依赖google.api.http注解映射路由,需与grpc服务共用监听器并正确注册到http mux中。

Grpc-gateway 是什么,它到底替你做了什么
Grpc-gateway 不是 gRPC 服务器,也不是 HTTP 代理,它是在 gRPC Server 启动后,**自动生成并注册一组 HTTP handler**,把 POST /v1/example 这类请求反向解析成对应的 gRPC ExampleRequest 结构体,再调用本地 gRPC 方法;响应时再把 ExampleResponse 序列化为 JSON 返回。它不转发请求到另一个服务,所有逻辑都在同一个进程内完成。
这意味着:你必须先写好 .proto 文件、定义好 gRPC service、生成 gRPC Go 代码(含 server 接口),然后 Grpc-gateway 才能基于同一份 proto 描述生成 HTTP 路由和绑定逻辑。
必须加的 proto 注解和生成命令不能漏
只写 service Example { rpc Do(...); } 是不够的。Grpc-gateway 依赖 google.api.http 扩展来知道哪个 RPC 对应哪个 HTTP 方法和路径。漏掉这行注解,生成的 gateway 代码里就根本没有路由注册。
- 在 .proto 中 import
google/api/annotations.proto和google/api/http.proto - 给每个 rpc 加
option (google.api.http) = { post: "/v1/example" body: "*" };——body: "*"表示整个请求体映射到 message 字段,不加会报400 Bad Request: missing required field - 生成时要同时跑两个插件:
protoc --go_out=... --go-grpc_out=... --grpc-gateway_out=... *.proto,其中--grpc-gateway_out必须带logtostderr=true参数才能看到生成失败提示
启动顺序和 mux 注册方式决定是否 404
Grpc-gateway 生成的是 runtime.NewServeMux(),它本身不监听端口,也不启动 HTTP server。你得手动把它挂到 http.ServeMux 或 gin.Engine 等框架里 —— 但要注意:gRPC Server 和 Gateway Mux 必须共用同一个 listener,或至少确保 Gateway 的 mux 在 gRPC Server 启动之后才开始接受请求。
用于端到端视频本地化流程的轻量编排器,路由至四个专注子技能——/wjs-transcribing-audio、/wjs-translating-subtitles...
常见错误是:先启动 HTTP server,再启动 gRPC server,结果 gateway mux 初始化时找不到 gRPC endpoint,导致所有请求返回 503 Service Unavailable。
- 推荐做法:用
grpc.Dial("localhost:9090", grpc.WithTransportCredentials(insecure.NewCredentials()))连本地 gRPC server(注意不是 dial localhost:8080) - 如果 gRPC server 用的是
grpc.Server默认监听,Gateway 就必须用grpc.WithBlock()确保连接建立后再启动 HTTP server - 不要把 gateway mux 直接传给
http.ListenAndServe(),而应封装进中间件链,否则OPTIONS预检、CORS、日志等逻辑会被绕过
JSON 编码行为和字段名映射容易踩坑
Grpc-gateway 默认用 jsonpb(已弃用)或 protoreflect + jsoniter 序列化,字段名默认按 proto 的 json_name 生成,不是 Go struct tag。比如 int64 user_id = 1 [json_name = "user_id"]; 生成 JSON 就是 "user_id": 123,不是 "UserId"。
- 若想让 JSON key 变成 camelCase,必须显式写
[json_name = "userId"],否则 gateway 不会自动转换 - 空值处理:proto3 中
string字段设为空字符串"",gateway 默认会序列化为"field": "";但设为nil(即未赋值)则直接 omit —— 这和 REST API 常见的“显式 null”语义不一致,需前端约定或加 wrapper 类型 - 时间戳字段(
google.protobuf.Timestamp)默认转成 RFC3339 字符串,如"2024-03-15T10:30:00Z";如果后端期望 Unix timestamp 整数,就得自定义UnmarshalJSON或用custom marshaler替换默认 encoder
真正麻烦的从来不是生成代码,而是 proto 定义和 HTTP 语义之间的隐含契约:路径怎么嵌套、query 怎么映射、body 该放哪、哪些字段允许空、时间格式要不要统一。这些细节一旦没对齐,前端拿到的就是一堆 400 或字段丢失,debug 时却查不到 gRPC 层——因为问题全卡在 gateway 解析阶段。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!










