浏览器无法直接调用gRPC,必须通过gRPC-Web网关转换协议;Envoy是唯一生产级选择,需启用grpc_web和cors过滤器,Go服务需开启反射并监听0.0.0.0,前端客户端须指定Envoy地址且匹配MIME类型。

浏览器不能直接调用 gRPC,这不是配置问题,是协议层硬限制:HTTP/2 + Protobuf vs HTTP/1.1 + JSON。想让前端直连 Go 后端 gRPC 服务,必须加一层 gRPC-Web 网关做协议转换——它不是可选组件,是必经通路。
为什么用 Envoy 而不是 grpcwebproxy
grpcwebproxy 已归档、不维护,本地 demo 可跑通,但一上生产就露馅:没 TLS 终止、没健康检查、没可观测性集成。Envoy 是唯一靠谱选择,尤其在 Kubernetes 场景下。
-
envoy.filters.http.grpc_web必须显式启用,否则浏览器发application/grpc-web+proto请求会静默返回415 Unsupported Media Type - Envoy 默认不转发 CORS 头,前端预检(
OPTIONS)会失败,得在http_filters里配envoy.filters.http.cors或交由后端处理 - 如果你用
docker-compose部署,Envoy 容器要能访问 Go gRPC server 的0.0.0.0:9090,不能绑127.0.0.1—— 容器网络里localhost指自己
Go gRPC server 需要改什么
业务代码完全不用动,但两个隐性条件不满足,网关就转不动:
初始化并管理阿里云SDK Go 客户端,涵盖 sync.Once 单例、goroutine 安全、endpoint 与 region 配置、VPC 端点及调试。
- 必须启用反射:
reflection.Register(server),否则前端调试工具(如grpcurl或 Web UI)查不到服务列表 - 监听地址必须是
0.0.0.0:9090,不是127.0.0.1:9090;否则 Envoy 在另一容器里根本连不上 - CORS 头建议由网关统一加(Envoy 支持),如果非要后端加,得用拦截器写
w.Header().Set("Access-Control-Allow-Origin", "*"),且注意Access-Control-Allow-Headers至少包含content-type和x-grpc-web
前端怎么调用才不报错
生成的 JS 客户端桩(protoc-gen-grpc-web 输出)默认走 http://localhost:8080(grpcwebproxy 默认端口),但你用的是 Envoy,得手动指定网关地址:
立即学习“go语言免费学习笔记(深入)”;
- 初始化 client 时传
host参数:new MyServiceClient("http://your-envoy-host:10000") - 流式 RPC(server-stream / bidi)需确认 Envoy 配置启用了
stream_idle_timeout,否则连接空闲 60s 后自动断开,前端onEnd收到status.UNKNOWN - 别用
fetch手动拼请求——gRPC-Web 协议头(如Content-Type: application/grpc-web+proto)和帧格式(length-delimited)很严格,手写极易出错
最易被忽略的是:Envoy 的 grpc_web filter 只识别特定 MIME 类型,而前端生成的 client 默认发 application/grpc-web+proto;如果后端 proto 编译时用了 --grpc-web_out=import_style=commonjs+dts,mode=grpcweb,但 Envoy 没配对,就会卡在 415。这个点不排查,其他都白搭。

















