浏览器不能直接调用grpc,因其依赖http/2和二进制protobuf,而浏览器仅支持http/1.1与json等文本协议;需通过grpc-web网关(如envoy或grpcwebproxy)做协议转换。

为什么浏览器不能直接调用 gRPC?
因为标准 gRPC 基于 HTTP/2 和二进制 Protobuf,而浏览器的 fetch 和 XMLHttpRequest 只支持 HTTP/1.1 和文本协议(如 JSON)。即使你把 .proto 编译成 Go 服务、再生成 JS 客户端,浏览器发出去的请求也会被后端拒绝——不是“没连上”,是协议层就不通。
所以必须加一层转换:把浏览器发来的 HTTP/1.1 + JSON(或二进制)请求,反向代理并转成 HTTP/2 + Protobuf,打给真正的 gRPC 服务。这个中间层,就是 gRPC-Web 网关。
用 grpcwebproxy 还是 Envoy?选哪个更稳?
grpcwebproxy(improbable-eng 开源)轻量、Go 写的、配置简单,但已归档不再维护;Envoy 是生产级选择,支持 TLS 终止、gRPC-Web / gRPC-HTTP/1.1 双模式、健康检查,且和 Kubernetes 集成顺滑。
如果你只是本地调试或 demo,用 grpcwebproxy 快速跑通没问题;但只要涉及 HTTPS、负载均衡、可观测性,必须上 Envoy。
立即学习“go语言免费学习笔记(深入)”;
- Envoy 的
grpc_webfilter 默认只处理application/grpc-web+proto和application/grpc-web-text请求头,别漏配 -
grpcwebproxy默认监听localhost:8080,转发到localhost:9090(你的 gRPC server),改端口得手动传--backend_addr - Envoy 配置里必须显式开启
http_filters中的envoy.filters.http.grpc_web,否则 415 错误静默出现
Go 后端要改哪些地方才能接住 gRPC-Web?
Go 的 gRPC server 本身不感知 gRPC-Web——它只管收 HTTP/2 流。真正要动的是「网关」和「客户端」两端。但你的 Go server 得满足两个隐性条件:
- 必须启用反射(
grpc.ReflectionServer),否则grpcurl或某些 Web 调试工具无法发现服务列表 - gRPC server 监听地址不能绑死
127.0.0.1,得用0.0.0.0:9090,否则 Envoy 在容器里连不上 - 不需要改
RegisterXXXServer逻辑,也不用重写 handler——gRPC-Web 网关负责协议转换,你的业务代码零侵入
唯一可能要加的,是 CORS 头。如果网关没代你加(比如 grpcwebproxy 默认不加),就得在 Go server 的拦截器里手动写 w.Header().Set("Access-Control-Allow-Origin", "*"),否则浏览器预检失败。
前端 JS 怎么发请求?用什么库?
别用原生 fetch 拼 gRPC-Web 协议——太容易出错。官方推荐 @improbable-eng/grpc-web,它会自动处理编码、流控、错误映射(比如把 gRPC 状态码转成 JS Error)。
注意三个关键点:
- 创建 client 时,
host填的是网关地址(如"http://localhost:8080"),不是后端 gRPC 地址 - 必须传
transport:开发用XHRTransport,生产建议换HttpTransport(支持 AbortController) - Protobuf 类型必须用
ts-proto或protoc-gen-grpc-web生成,且 import 路径要和import语句严格一致,否则 runtime 找不到service定义
示例片段:
const client = new GreeterClient("http://localhost:8080", { transport });<br>client.sayHello(new HelloRequest().setName("world")).then(r => console.log(r.getMessage()));
最常被忽略的是网关和后端之间的网络连通性验证——先用 curl -v http://localhost:8080/my.Service/SayHello 看是否返回 404(说明网关通),再用 grpcurl -plaintext localhost:9090 list 看后端是否真在跑。两头都通了,才去调前端代码。否则卡在某一层,日志里全是 503 或空响应。










