In the previous research Browser Push Solution, I summarized several possible ways to support browsers to receive Server Push, although not all of them can work, but it is still very enlightening. However, one of the ways I didn’t understand too well is how gRPC-Web is implemented, so in this article, I would like to understand 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, one response model)
- Server Streaming calls (one request, but multiple response models)
However, it does not mean that you can directly call a common gRPC Server in another language directly with gRPC Web, because their protocols are different, so you need a gRPC Web proxy in between, the official recommendation is Envoy, and the official implementation of Envoy as the official way to iterate.
gRPC Web’s protocol implementation
As mentioned earlier, gRPC Web cannot communicate directly with a normal gRPC Server because their protocols are different. We all know that ordinary gRPC is based on HTTP2 implementation, but gRPC Web is based on HTTP/1.1 implementation, so it needs a Proxy for conversion, so it needs a middleware like Envoy to convert the protocol.
In fact, in my previous research, I found that Websocket is still the only browser method that can stably support Bidirectional Stream, but why doesn’t gRPC Web use Websocket? This question is answered in the official documentation of gRPC Web: Websocket is not compatible with HTTP, especially Websockets are not compatible with HTTP, especially with the ubiquitous Web infrastructure. But personally, I actually disagree, because in my usage and scenarios I’ve seen (both 2B and 2C scenarios), Websocket support is everywhere and not as difficult as one might think.
You say that 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?
OK，we have just introduced some theory, and then we will follow the official guide to run the gRPC Web demo，and to check whther the request is following the therory we just introduced：
[email@example.com]# git clone https://github.com/grpc/grpc-web
[firstname.lastname@example.org]# cd grpc-web
[email@example.com]# docker-compose pull prereqs node-server envoy commonjs-client
[firstname.lastname@example.org]# docker-compose up -d node-server envoy commonjs-client
|Figure 1：gRPC Web Request
|Figure 2：gRPC Web Request Success
From this simple demo, what we can take is that the request is by HTTP Post method, and then received by the Envoy at the backend. Then transfered to the general gRPC protocol, after the Envoy received the response, it will transfer the response to Post response, but the Post response is an encoded string, and we need to decode：
|Figure 3：gRPC Response Decode
Ok, this is my simple understanding of gRPC Web, from this understanding we can see that the implementation of gRPC Web is still relatively inconvenient, and the features supported are relatively single, and also requires proxy support, then since all proxy support, then why I do not go on the API gateway? But as a learning experience, there is no harm.