如何将 API 定义的 gRPC 引入 Web 浏览器
How to bring a gRPC defined API to the web browser
我们想为我们的 gRPC 微服务构建一个 Javascript/HTML 图形用户界面。由于浏览器端不支持gRPC,我们想到了使用web-sockets连接一个node.js服务器,通过grpc调用目标服务。
我们努力寻找一个优雅的解决方案来做到这一点。特别是,因为我们使用 gRPC 流在我们的微服务之间推送事件。
看来我们需要第二个RPC系统,只是为了前端和node.js服务器之间的通信。这似乎是很多开销和必须维护的额外代码。
有没有人有过这样做的经验或知道如何解决这个问题?
抱歉,目前还没有适合您的答案。
从浏览器支持流式 RPC 完全需要浏览器支持 HTTP2 预告片,而在撰写本回答时,它们还不支持。
有关该主题的讨论,请参阅 this issue。
否则,是的,您需要 WebSocket 和 gRPC 之间的完整转换系统。也许从 grpc-gateway 中获得灵感可能是这样一个项目的开始,但这仍然是一个很长的路要走。
https://github.com/tmc/grpc-websocket-proxy 听起来可能会满足您的需求。这会将 json 通过网络套接字转换为 grpc(grpc-gateway 之上的层)。
https://github.com/grpc/ are currently building a js implementation.
的 grpc 人
重现在https://github.com/grpc/grpc-web (gives 404 ->) which is currently (2016-12-20) in early access so you need to request access。
GRPC Bus WebSocket Proxy 通过代理 WebSocket 连接上的所有 GRPC 调用来实现这一点,为您提供看起来与浏览器中的节点 GRPC API 非常相似的东西。与 GRPC-Gateway 不同,它适用于流式请求和流式响应,以及非流式调用。
同时有服务器和客户端组件。
通过执行 docker run gabrielgrant/grpc-bus-websocket-proxy
,GRPC Bus WebSocket Proxy server 可以是 运行 和 Docker
在浏览器端,您需要安装 GRPC Bus WebSocket Proxy client 和 npm install grpc-bus-websocket-client
然后创建一个新的 GBC 对象:new GBC(<grpc-bus-websocket-proxy address>, <protofile-url>, <service map>)
例如:
var GBC = require("grpc-bus-websocket-client");
new GBC("ws://localhost:8080/", 'helloworld.proto', {helloworld: {Greeter: 'localhost:50051'}})
.connect()
.then(function(gbc) {
gbc.services.helloworld.Greeter.sayHello({name: 'Gabriel'}, function(err, res){
console.log(res);
}); // --> Hello Gabriel
});
客户端库希望能够使用 AJAX 请求下载 .proto
文件。 service-map
提供代理服务器所见的原型文件中定义的不同服务的 URL。
有关详细信息,请参阅 GRPC Bus WebSocket Proxy client README
编辑:自 2018 年 10 月 23 日起 gRPC-Web project is GA,这可能是解决您问题的最 official/standardized 方法。 (即使现在已经是 2018 年了……;))
来自 GA 博客:"gRPC-Web, just like gRPC, lets you define the service “contract” between client (web) and backend gRPC services using Protocol Buffers. The client can then be auto generated. [...]"
我们最近构建了 gRPC-Web (https://github.com/improbable-eng/grpc-web) - 一个遵循提议的 gRPC-Web 协议的浏览器客户端和服务器包装器。该回购协议中的示例应该提供一个很好的起点。
如果您使用的是 Golang,则需要独立代理或 gRPC 服务器包装器。 proxy/wrapper 修改响应以将预告片打包在响应正文中,以便浏览器可以读取它们。
披露:我是该项目的维护者。
查看当前基于 Web 的 gRPC 解决方案,以下是撰写本文时可用的解决方案(以及我发现的):
- gRPC-web:客户端需要 TypeScript
- gRPC-web-proxy: 需要 Go
- gRPC-gateway: 需要.proto修改和修饰
- gRPC-bus-websocket-proxy-server:
在撰写本文档时它缺少测试并且似乎已被遗弃(编辑:查看原作者的评论!)
- gRPC-dynamic-gateway:对于简单的 gRPC 服务来说有点矫枉过正,身份验证很尴尬
- gRPC-bus: 需要运输东西
我还想无耻地插入我自己为公司编写的解决方案,它在生产中用于代理对 gRPC 服务的请求,该服务仅包括一元和服务器流调用:
代码的每一寸都被测试覆盖。它是一个 Express 中间件,因此不需要对您的 gRPC 设置进行额外修改。您还可以将 HTTP 身份验证委托给 Express(例如使用 Passport)。
官方 grpc-web(测试版)实施于 2018 年 3 月 23 日发布。您可以在
找到它
以下说明摘自自述文件:
定义您的 gRPC 服务:
service EchoService {
rpc Echo(EchoRequest) returns (EchoResponse);
rpc ServerStreamingEcho(ServerStreamingEchoRequest)
returns (stream ServerStreamingEchoResponse);
}
用你想要的任何语言构建服务器。
创建您的 JS 客户端以从浏览器进行调用:
var echoService = new proto.grpc.gateway.testing.EchoServiceClient(
'http://localhost:8080');
进行一元 RPC 调用
var unaryRequest = new proto.grpc.gateway.testing.EchoRequest();
unaryRequest.setMessage(msg);
echoService.echo(unaryRequest, {},
function(err, response) {
console.log(response.getMessage());
});
支持从服务器到浏览器的流:
var stream = echoService.serverStreamingEcho(streamRequest, {});
stream.on('data', function(response) {
console.log(response.getMessage());
});
不支持双向流:
这是一项正在进行的工作,grpc-web roadmap. While there is an example protobuf showing bidi streaming, this comment 明确表示此示例尚未实际运行。
希望这会很快改变。 :)
我看到很多答案都没有指向基于 WebSocket 的双向解决方案,因为 OP 要求浏览器支持。
您可以使用 JSON-RPC 而不是 gRPC,以通过 WebSocket 获得 双向 RPC,它支持更多,包括 WebRTC(浏览器到浏览器) .
如果你真的需要这种类型的序列化,我想可以修改它以支持 gRPC。
但是,对于浏览器选项卡到浏览器选项卡,请求对象不会被序列化,而是在本地传输,与 NodeJS 集群或线程工作者相同,这提供了更多的性能。
此外,您可以将 "pointers" 传输到 SharedArrayBuffer,而不是通过 gRPC 格式序列化。
JSONV8中的序列化和反序列化也是无敌的
我们想为我们的 gRPC 微服务构建一个 Javascript/HTML 图形用户界面。由于浏览器端不支持gRPC,我们想到了使用web-sockets连接一个node.js服务器,通过grpc调用目标服务。 我们努力寻找一个优雅的解决方案来做到这一点。特别是,因为我们使用 gRPC 流在我们的微服务之间推送事件。 看来我们需要第二个RPC系统,只是为了前端和node.js服务器之间的通信。这似乎是很多开销和必须维护的额外代码。
有没有人有过这样做的经验或知道如何解决这个问题?
抱歉,目前还没有适合您的答案。
从浏览器支持流式 RPC 完全需要浏览器支持 HTTP2 预告片,而在撰写本回答时,它们还不支持。
有关该主题的讨论,请参阅 this issue。
否则,是的,您需要 WebSocket 和 gRPC 之间的完整转换系统。也许从 grpc-gateway 中获得灵感可能是这样一个项目的开始,但这仍然是一个很长的路要走。
https://github.com/tmc/grpc-websocket-proxy 听起来可能会满足您的需求。这会将 json 通过网络套接字转换为 grpc(grpc-gateway 之上的层)。
https://github.com/grpc/ are currently building a js implementation.
的 grpc 人重现在https://github.com/grpc/grpc-web (gives 404 ->) which is currently (2016-12-20) in early access so you need to request access。
GRPC Bus WebSocket Proxy 通过代理 WebSocket 连接上的所有 GRPC 调用来实现这一点,为您提供看起来与浏览器中的节点 GRPC API 非常相似的东西。与 GRPC-Gateway 不同,它适用于流式请求和流式响应,以及非流式调用。
同时有服务器和客户端组件。
通过执行 docker run gabrielgrant/grpc-bus-websocket-proxy
在浏览器端,您需要安装 GRPC Bus WebSocket Proxy client 和 npm install grpc-bus-websocket-client
然后创建一个新的 GBC 对象:new GBC(<grpc-bus-websocket-proxy address>, <protofile-url>, <service map>)
例如:
var GBC = require("grpc-bus-websocket-client");
new GBC("ws://localhost:8080/", 'helloworld.proto', {helloworld: {Greeter: 'localhost:50051'}})
.connect()
.then(function(gbc) {
gbc.services.helloworld.Greeter.sayHello({name: 'Gabriel'}, function(err, res){
console.log(res);
}); // --> Hello Gabriel
});
客户端库希望能够使用 AJAX 请求下载 .proto
文件。 service-map
提供代理服务器所见的原型文件中定义的不同服务的 URL。
有关详细信息,请参阅 GRPC Bus WebSocket Proxy client README
编辑:自 2018 年 10 月 23 日起 gRPC-Web project is GA,这可能是解决您问题的最 official/standardized 方法。 (即使现在已经是 2018 年了……;))
来自 GA 博客:"gRPC-Web, just like gRPC, lets you define the service “contract” between client (web) and backend gRPC services using Protocol Buffers. The client can then be auto generated. [...]"
我们最近构建了 gRPC-Web (https://github.com/improbable-eng/grpc-web) - 一个遵循提议的 gRPC-Web 协议的浏览器客户端和服务器包装器。该回购协议中的示例应该提供一个很好的起点。
如果您使用的是 Golang,则需要独立代理或 gRPC 服务器包装器。 proxy/wrapper 修改响应以将预告片打包在响应正文中,以便浏览器可以读取它们。
披露:我是该项目的维护者。
查看当前基于 Web 的 gRPC 解决方案,以下是撰写本文时可用的解决方案(以及我发现的):
- gRPC-web:客户端需要 TypeScript
- gRPC-web-proxy: 需要 Go
- gRPC-gateway: 需要.proto修改和修饰
- gRPC-bus-websocket-proxy-server:
在撰写本文档时它缺少测试并且似乎已被遗弃(编辑:查看原作者的评论!) - gRPC-dynamic-gateway:对于简单的 gRPC 服务来说有点矫枉过正,身份验证很尴尬
- gRPC-bus: 需要运输东西
我还想无耻地插入我自己为公司编写的解决方案,它在生产中用于代理对 gRPC 服务的请求,该服务仅包括一元和服务器流调用:
代码的每一寸都被测试覆盖。它是一个 Express 中间件,因此不需要对您的 gRPC 设置进行额外修改。您还可以将 HTTP 身份验证委托给 Express(例如使用 Passport)。
官方 grpc-web(测试版)实施于 2018 年 3 月 23 日发布。您可以在
找到它以下说明摘自自述文件:
定义您的 gRPC 服务:
service EchoService {
rpc Echo(EchoRequest) returns (EchoResponse);
rpc ServerStreamingEcho(ServerStreamingEchoRequest)
returns (stream ServerStreamingEchoResponse);
}
用你想要的任何语言构建服务器。
创建您的 JS 客户端以从浏览器进行调用:
var echoService = new proto.grpc.gateway.testing.EchoServiceClient(
'http://localhost:8080');
进行一元 RPC 调用
var unaryRequest = new proto.grpc.gateway.testing.EchoRequest();
unaryRequest.setMessage(msg);
echoService.echo(unaryRequest, {},
function(err, response) {
console.log(response.getMessage());
});
支持从服务器到浏览器的流:
var stream = echoService.serverStreamingEcho(streamRequest, {});
stream.on('data', function(response) {
console.log(response.getMessage());
});
不支持双向流:
这是一项正在进行的工作,grpc-web roadmap. While there is an example protobuf showing bidi streaming, this comment 明确表示此示例尚未实际运行。
希望这会很快改变。 :)
我看到很多答案都没有指向基于 WebSocket 的双向解决方案,因为 OP 要求浏览器支持。
您可以使用 JSON-RPC 而不是 gRPC,以通过 WebSocket 获得 双向 RPC,它支持更多,包括 WebRTC(浏览器到浏览器) .
如果你真的需要这种类型的序列化,我想可以修改它以支持 gRPC。
但是,对于浏览器选项卡到浏览器选项卡,请求对象不会被序列化,而是在本地传输,与 NodeJS 集群或线程工作者相同,这提供了更多的性能。
此外,您可以将 "pointers" 传输到 SharedArrayBuffer,而不是通过 gRPC 格式序列化。
JSONV8中的序列化和反序列化也是无敌的