浏览器无法直接调用grpc因不支持http/2原生帧,需通过grpc-web网关(如envoy)适配http/1.1;客户端须匹配服务名、开启cors、正确配置host与proto生成参数;双向流不被原生支持,仅模拟实现。

为什么浏览器直接调用 gRPC 会失败?
因为浏览器不支持 HTTP/2 原生帧,而标准 gRPC 依赖 HTTP/2 的二进制流和头部压缩。你看到的 net::ERR_HTTP2_PROTOCOL_ERROR 或空响应,基本都卡在这儿。
- 浏览器只能发 HTTP/1.1 请求(即使服务端启了 HTTP/2)
-
gRPC-Web是个适配层:把 HTTP/1.1 的 POST 请求 + base64 编码 payload,转成后端能识别的 gRPC 调用 - 它不是协议替代,而是「前端代理协议」——必须搭配一个转换网关(如
envoy或grpcwebproxy)
如何让 Go 后端真正支持 gRPC-Web?
Go 本身不原生提供 gRPC-Web server,必须加一层反向代理。直接在 http.ServeMux 上注册 gRPC handler 是无效的。
- 用
envoy是最稳的选择:官方推荐、支持双向流、可复用 TLS 和路由配置 -
grpcwebproxy(improbable-eng/grpc-web)轻量但已归档,新项目慎用 - 不要用
grpc-go的grpc.WithInsecure()直连浏览器——它只对 gRPC 客户端有效,浏览器发不出合法帧
示例 envoy 配置片段:
filter_chains:
- filters:
- name: envoy.filters.network.http_connection_manager
typed_config:
http_filters:
- name: envoy.filters.http.grpc_web
- name: envoy.filters.http.router
grpc-web 客户端怎么写才不报 503 Service Unavailable?
这通常不是代码问题,而是网关没转发到后端 gRPC server,或路径没对齐。
立即学习“go语言免费学习笔记(深入)”;
- 前端
grpc-webclient 默认发请求到/path/to/Service/Method,必须和后端 proto service 名完全一致(大小写敏感) - 确保
envoy的cluster指向的是后端 gRPC server 的 HTTP/2 地址(如grpc-backend:9090),不是它暴露给浏览器的 HTTP/1.1 端口 - 如果用
grpcurl能通但前端不通,大概率是跨域没开:envoy需显式启用CORSfilter,并允许Content-Type和Grpc-Encoding
关键参数别漏:
-
withCredentials: true(如果带 cookie) -
host必须是网关地址,不是后端 gRPC 地址 - proto 生成时用
--js_out=import_style=commonjs,binary,否则 runtime 找不到jspb序列化逻辑
为什么双向流(stream)在浏览器里总断?
gRPC-Web 规范只定义了「浏览器发起的单向流」(client streaming)和「服务器推送的单向流」(server streaming),不支持真正的双向流(bidi streaming)。
- 浏览器端用
grpc-web调bidi方法,实际被降级为「轮询长连接」或「Server-Sent Events」模拟,延迟高、易超时 - 真需要低延迟双向通信,该换
WebSocket+ 自定义协议,别硬套gRPC-Web - 如果非要用,确保
envoy开了grpc_web_filter的allow_connect,且后端 gRPC server 支持CONNECT方法(Go 的grpc-go默认不支持,得自己 wrap handler)
复杂点在于:协议层妥协了,但业务逻辑还按双向流设计,很容易在重连、缓冲、序号同步上出错。浏览器里跑流,先想清楚是不是真需要它。










