为何gRPC在前端开发中未能普及
后端开发者习惯于使用gRPC、Protobuf和Avro进行网络通信。但转向前端时,REST变得繁琐:没有便捷的契约,Swagger需要双方同步。JSON带来复杂性——后端编组数据,前端担心破坏性变更。请求变成类似resp?.body?[i]?.creds?.card?.number的链式调用。
gRPC通过类型化和代码生成解决了这些问题。那么为什么它在前端不被使用呢?
OpenAPI和Swagger代码生成的问题
Swagger的自动生成不保证稳定性。后端开发者更改字段却忘记更新规范——前端就会崩溃。组织问题不可避免:休假、紧急任务。
Facebook的GraphQL曾承诺解决方案:严格模式、内省、代码生成。前端开发者受益,但后端承担了缺点:
- 客户端可以请求任意深度:从
{ user { id name } }到递归的posts { comments { author { ... } } }。 - 没有直接映射到数据库模型——需要解析器和联合类型。
- N+1查询问题。
DataLoader、持久化查询和深度限制增加了后端的复杂性。在Go中,GraphQL包尤其不便。
gRPC-Web:失去优势的折中方案
gRPC-Web看起来像解决方案:Protobuf、代码生成。但它不是真正的gRPC。
浏览器支持HTTP/2+,但没有完全控制权:
- 没有连接、帧或流管理——一切都通过
fetch('/api')进行。 - 浏览器→代理通过HTTP/1.1,代理→后端通过HTTP/2。收益仅在后端。
- 需要代理基础设施。
gRPC-Web变成了数据格式,而非传输协议。优势尽失。
根本问题:浏览器限制
浏览器出于安全原因阻止低级访问。来自网站的JS代码有网络访问权限,但完整的HTTP/2+帧将允许:
- 扫描本地网络。
- 攻击本地主机。
- 绕过防火墙。
- 通过用户连接进行DDoS攻击。
HTTP/1.1因沙箱化而安全:无套接字,有限的fetch和WebSocket。浏览器管理HTTP/2+中的多路复用和头部压缩是为了自身优化,而非JS。
有前景的替代方案
解决方案存在,但无一通用:
- tRPC:适用于TypeScript单体仓库。类型直接导入,无需代码生成,通过HTTP传输。
- Connect协议(Buf):gRPC之上的层,用于浏览器中的fetch,带代码生成。
- WebTransport:用于沙箱中HTTP/3流的实验性API。未来开发的方向。
关键要点
- REST因通用性而主导,尽管契约不便。
- 浏览器沙箱阻止低级HTTP/2+以防范攻击。
- gRPC-Web失去关键特性:流式传输、多路复用。
- tRPC、Connect和WebTransport是针对特定技术栈的利基解决方案。
- 行业正通过WebTransport向沙箱化流访问迈进。
在通用契约出现前,REST将保持标准。Curl将继续用于调试。
— Editorial Team
暂无评论。