如何将gRPC定义的API带到Web浏览器中

84
我们希望为我们的gRPC微服务构建一个JavaScript/HTML GUI界面。由于gRPC不支持浏览器端,我们考虑使用WebSockets连接到一个node.js服务器,该服务器通过grpc调用目标服务。
我们很难找到一个优雅的解决方案。特别是,因为我们使用gRPC流在微服务之间推送事件。
似乎我们需要第二个RPC系统来在前端和node.js服务器之间通信。这似乎会带来大量开销和额外的代码需要维护。
有没有人有像这样的经验或者有想法如何解决这个问题?

请查看Wildcard API,它是一个小工具,可以让您轻松地在前端和Node.js服务器之间创建RPC API。它类似于gRPC,但更简单且更易于使用。声明:我是该工具的作者。 - brillout
8个回答

45
编辑:自2018年10月23日起,gRPC-Web项目已经正式发布,这可能是解决您问题的最官方/标准化的方式。(即使现在已经是2018年了... ;) )
从GA-Blog中可以看到:“gRPC-Web和gRPC一样,允许您使用协议缓冲区定义客户端(Web)和后端gRPC服务之间的服务“合同”。然后可以自动生成客户端。[...]" 我们最近构建了gRPC-Web(https://github.com/improbable-eng/grpc-web)- 一个遵循提议的gRPC-Web协议的浏览器客户端和服务器包装器。该存储库中的示例应该是一个很好的起点。
如果您使用的是Golang,它需要一个独立的代理或包装器来处理您的gRPC服务器。代理/包装器会修改响应,将尾部信息封装在响应体中,以便浏览器可以读取。
声明:我是该项目的维护者。

4
杀手级特性现在将是能够为任何proto文件创建一个类似于Swagger所做的HTML playground页面的能力。这样,任何gRPC服务都可以轻松地通过浏览器进行测试。 - Setheron
1
@Marcus,你说它遵循“Proposed gRPC-Web protocol”。这是与官方https://github.com/grpc/grpc-web实现使用的相同协议吗(最近公开发布),因此这些实现是否兼容?还是您指的是自己提出的协议? - Matthijs Kooijman
@Setheron,你能给我一个关于这个非常重要的特性的示例或描述的链接吗?我还没有找到 :( 我有一个使用gRPC-Web应用程序(node.js)与二进制(base64)消息以及像官方文档中一样使用Envoy代理的应用程序,并且我想要一个类似于Swagger的工具来测试我的应用程序。 - razon
这个项目能够与WordPress(PHP)连接吗? - Jeff Bootsholz

18
很遗憾,目前还没有一个好的答案可以回答您的问题。
从浏览器完全支持流式RPC需要HTTP2尾部支持,但在回答撰写时,浏览器尚未支持。
请参见此问题以了解该主题的讨论。
否则,您需要在WebSockets和gRPC之间使用完整的转换系统。也许从grpc-gateway获取灵感可能是这样一个项目的开始,但这仍然是一个非常遥远的目标。

谢谢您的回答!我已经了解了http trailers的问题。甚至有人做了一个补丁,使得在浏览器中使用grpc而不需要流式传输成为可能。grpc-gateway项目是一个有用的提示。我们现在可能会使用dnode来创建网关... - Oliver
1
是的,如果你忽略流式传输,那么从浏览器使用gRPC完全是可能的。 - Nicolas Noble
@NicolasNoble - 非常好。有没有一个来自浏览器的非流式gRPC调用的例子? - AlikElzin-kilaka
不幸的是还没有。我只是在理论上讲。但更改应该很小。 - Nicolas Noble
1
我们正在收集对早期访问计划感兴趣的人的姓名,请在此处添加您的姓名,我们会尽快分享我们所拥有的信息。 - Nicolas Noble
显示剩余2条评论

11

2018年3月23日发布了官方的grpc-web(beta)实现。您可以在以下网址找到它:

https://github.com/grpc/grpc-web

以下说明摘自README:

定义您的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 路线图 中。虽然有一个示例 protobuf 显示了双向流式传输,但这条评论表明此示例目前尚未实际工作。

希望很快会有所改变。:)


1
你确定双向流被支持了吗?你的双向流示例似乎只展示了服务器流,而你的服务器流示例仅展示了一个没有任何流的一元请求。README也只提到了服务器流,这让我怀疑客户端或双向流是否被支持。你能否澄清一下? - Matthijs Kooijman
2
@MatthijsKooijman他们的回声示例展示了客户端和全双工流:https://github.com/grpc/grpc-web/blob/master/net/grpc/gateway/examples/echo/echo.proto#L96 - Cody A. Ray
1
看起来这个示例仅供参考,实际上并不被支持。请参阅 https://github.com/grpc/grpc-web/issues/24#issuecomment-303285538,该评论明确说明了这个示例的情况。 - Matthijs Kooijman
1
@MatthijsKooijman看起来你是对的。我已经更新了我的答案以反映这一点(并包括了路线图和评论的链接)。谢谢! - Cody A. Ray
1
现在你从你的回答中删除了流媒体服务器示例(之前你错误地将其标记为双向流)。 - Matthijs Kooijman
有趣的 https://github.com/grpc/grpc-web/blob/01c9ac61b87279c0f592acbc6155760c1b63ee5e/net/grpc/gateway/examples/echo/echotest.html - Alex Punnen

7

这个仓库现在已经开放,另外请参考Cody的答案。 - Matthijs Kooijman

7

3
GRPC Bus WebSocket Proxy可以通过代理所有GRPC调用到WebSocket连接来实现这一点,从而为您提供在浏览器中非常类似于Node GRPC API的东西。与GRPC-Gateway不同,它适用于流请求、流响应以及非流调用。
既有服务器组件,也有客户端组件。 GRPC Bus WebSocket Proxy服务器可以通过运行docker run gabrielgrant/grpc-bus-websocket-proxy来使用Docker运行。
在浏览器端,您需要使用npm install grpc-bus-websocket-client安装GRPC Bus WebSocket Proxy客户端
然后使用以下命令创建一个新的GBC对象:new GBC(<grpc-bus-websocket-proxy地址>, <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,这些服务在代理服务器中定义并在您的proto文件中看到。
有关详细信息,请参阅GRPC Bus WebSocket Proxy client README

2
我看到很多答案都没有指向一个WebSocket上的双向解决方案,正如提问者要求的那样支持浏览器。
您可以使用JSON-RPC代替gRPC,以获得WebSocket上的双向RPC,它支持更多功能,包括WebRTC(浏览器对浏览器)。
我想如果您真的需要这种类型的序列化,它可能可以被修改为支持gRPC。
但是,对于浏览器标签之间,请求对象不会被序列化,并且会在本地传输,与NodeJS集群或线程工作器相同,这提供了更高的性能。
此外,您可以传输指向SharedArrayBuffer的“指针”,而不是通过gRPC格式进行序列化。
V8中的JSON序列化和反序列化也是无与伦比的。

https://github.com/bigstepinc/jsonrpc-bidirectional


0

看目前在Web上使用gRPC的解决方案,以下是我在撰写此文时发现的可用选项:

我也想厚颜无耻地推销一下我为公司编写的解决方案,它正在生产中用于代理请求到仅包含一元和服务器流调用的gRPC服务:

代码的每一行都经过了测试。它是一个Express中间件,因此不需要对您的gRPC设置进行额外的修改。您还可以将HTTP身份验证委托给Express(例如使用Passport)。


嘿!grpc-express看起来很酷,特别适合那些使用Express但不需要客户端流的人。我很好奇你希望为gRPC-bus-websocket-proxy-server添加哪些额外的测试?它是对grpc-bus的一个相当薄的包装/传输层(已经过很好的单元测试),所以我不认为复制这些测试有什么意义,而“演示”实际上就是验收测试。无论如何,我们正在Pachyderm中积极使用它,因为它基本上只需要工作就可以了 :) - Gabriel Grant

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接