gRPC-Gateway 是独立 HTTP/1.1 服务器,将 HTTP 请求反向代理至本地 gRPC 服务;需确保 gRPC 服务已启动并地址匹配,正确使用 google.api.http 注解、protoc 重生成代码,并用 http.Server 而非 ListenAndServe 启动。
gRPC-Gateway 不是“让 gRPC 接口自动变 HTTP”
它是一个独立运行的 http/1.1 服务器,只做一件事:把 post /v1/user 这类请求,反向代理成对本地 grpc 服务(如 user.get)的调用。grpc 服务必须先启动、监听明确地址(推荐 127.0.0.1:9090),否则你会看到 rpc error: code = unavailable desc = connection refused。
常见错误包括:
- grpc-gateway 启动时用
localhost:9090连接,但 gRPC server 绑定的是127.0.0.1:9090(Docker 或 IPv6 环境下解析不一致) - 误以为生成的
user.pb.gw.go是 gRPC client —— 它只是 HTTP handler,不发任何 gRPC 请求 - 没在
protoc命令中加入googleapis路径,导致google/api/annotations.proto找不到
proto 文件里必须写对 google.api.http 注解
注解不是可选装饰,而是 grpc-gateway 生成路由和参数绑定的唯一依据。漏掉 import "google/api/annotations.proto" 或写错字段名,会导致生成代码无路由、参数全丢、404 或 400。
关键写法示例:
import "google/api/annotations.proto";
message GetUserRequest {
uint32 user_id = 1;
}
service UserService {
rpc GetUser(GetUserRequest) returns (GetUserResponse) {
option (google.api.http) = {
get: "/api/v1/user/{user_id}" // 路径参数必须与字段名完全一致
};
}
rpc CreateUser(CreateUserRequest) returns (CreateUserResponse) {
option (google.api.http) = {
post: "/api/v1/user"
body: "*" // 表示整个 JSON body 映射到消息体;若只映射部分字段,写具体字段名如 "user.username"
};
}
}
注意:body: "*" 和 body: "user" 行为完全不同,后者要求 JSON 顶层有 {"user": {...}} 包裹。
生成 gateway 代码必须重跑 protoc,不能靠手写
每次改了 .proto,哪怕只加一个字段或改个路径,都必须重新执行 protoc 命令。否则 user.pb.gw.go 里的路由注册、JSON 字段名、嵌套结构解析逻辑全部失效。
典型命令(v2 版本):
通过 `dcc-mcp-cli` 命令行工具控制实时 DCC 主机(Maya、Blender、Houdini、Photoshop、3ds Max 以及自定义的 Studio 工具)。 针对 ClawHub、OpenClaw、Cursor、Claude 和支持 shell 的 Agent 主机:验证网关健康状态、列出已注册的 DCC 实例、搜索工具、检查 Schema、调用工具——全程无需直接编写或发送 MCP 请求。 若系统中未安装 `dcc-mcp-cli`,需先征得用户同意,再从 GitHub
protoc -I . \ -I $GOPATH/src/github.com/grpc-ecosystem/grpc-gateway/v2/third_party/googleapis \ --grpc-gateway_out=logtostderr=true:. \ user.proto
必须确保:
-
protoc-gen-grpc-gateway已安装且在$PATH中(go install github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-grpc-gateway@latest) - 没混用 v1 和 v2 插件(v2 不再支持
protoc-gen-swagger,改用protoc-gen-openapiv2) - 生成目录与
go_package选项匹配,否则 import 路径出错
HTTP server 注册 gateway handler 时别用 http.ListenAndServe
http.ListenAndServe 启动的 server 缺少中间件支持、context 生命周期管理能力,也不方便集成 CORS、gzip、超时等生产必需功能。
正确做法是用标准 http.Server,并显式注册 gateway handler:
gwMux := runtime.NewServeMux()
if err := pb.RegisterUserServiceHandler(ctx, gwMux, conn); err != nil {
log.Fatal(err)
}
httpServer := &http.Server{
Addr: ":8080",
Handler: cors.Default().Handler(gwMux), // 加 CORS
}
httpServer.ListenAndServe()
重点:
-
conn是已连上 gRPC server 的*grpc.ClientConn,不是新 dial 的 -
runtime.NewServeMux()必须复用,不能每次请求都新建 - 不要把 gRPC server 的
ServeHTTP和 gateway handler 混在同一 mux 下——它们协议不兼容,HTTP/2 流量会直接失败
最易被忽略的一点:gateway handler 和 gRPC server 的健康检查、日志上下文、panic 恢复策略要保持一致,否则线上排障时两个服务的日志时间线和 trace ID 对不上。

















