In the previous research on browser Push, I summarised a number of possible ways to support browsers receiving Server Push, not all of which work, but are still very enlightening. However, one of the ways I didn’t quite understand was how gRPC-Web was implemented, so in this article I’d like to look at how gRPC-Web implements Bidirectional Stream.

Features supported by gRPC Web

As of today, gRPC Web supports only two types of calls, namely

  • Unary RPC calls (one request with one response model)
  • Server Streaming calls (one request, but multiple response models)

However, it does not mean that you can use gRPC Web to call a normal gRPC Server in another language directly, as their protocols are different, so you need a gRPC Web proxy in between, and the official recommendation is Envoy.

Protocol implementation of gRPC Web

As mentioned earlier, gRPC Web cannot communicate directly with a normal gRPC Server because their protocols are different. We all know that normal gRPC is based on the HTTP2 implementation, but gRPC Web is based on the HTTP/1.1 implementation, so a Proxy is needed to convert between them, so this is where middleware like Envoy comes in to convert the protocol.

In my previous research, I found that Websocket is probably the only browser method that can support Bidirectional Stream consistently, but why doesn’t gRPC Web use Websocket? This question is answered in the official gRPC Web documentation: Websockets are not compatible with HTTP, especially with the web infrastructure that is everywhere. But personally, I actually disagree, because in the scenarios I’ve used and seen (both 2B and 2C scenarios), Websocket support is everywhere and not as difficult as one might think.

You say it’s because Websocket doesn’t work out of the box (so that other web infrastructures can support it), but the current gRPC web implementation doesn’t look very good to me either because you only support unary and Server Streaming, so wouldn’t it be better to switch to Websocket and be able to support full gRPC functionality?

An example

OK, some theoretical aspects have been covered, so let’s follow the official guide and run a gRPC Web example and see if the request is really implemented as in the previous analysis.

[root@liqiang.io]# git clone https://github.com/grpc/grpc-web
[root@liqiang.io]# cd grpc-web
[root@liqiang.io]# docker-compose pull prereqs node-server envoy commonjs-client
[root@liqiang.io]# docker-compose up -d node-server envoy commonjs-client

gRPC Web Requests


As you can see from this simple example, the request is initiated by an HTTP Post request, which is then received by Envoy on the back end and converted to the generic gRPC protocol; the response is then received and then converted to a Post response, but the Post response is an encoded string that still needs to be decoded.

gRPC Response


Ok, this is a brief introduction to gRPC Web, from which I can see that the implementation of gRPC Web is still rather inconvenient, and the features supported are relatively simple, and proxy support is also required, so if proxy support is available, why don’t I use the API gateway? But as a learning experience, it doesn’t hurt.