DEV Community

Cover image for Why gRPC is not natively supported by Browsers
Thanapon Jindapitak
Thanapon Jindapitak

Posted on

Why gRPC is not natively supported by Browsers

Hi there,

Hope that this blog will give everyone some idea of why gRPC is not natively supported by the Browsers.

Many mentioned "because of Browser limitation".
But they don't explain why.

Even in the https://grpc.io blog says this

It is currently impossible to implement the HTTP/2 gRPC spec3 in the browser, as there is simply no browser API with enough fine-grained control over the requests. For example: there is no way to force the use of HTTP/2, and even if there was, raw HTTP/2 frames are inaccessible in browsers

https://grpc.io/blog/state-of-grpc-web/#the-grpc-web-spec

No one give explanations about why we cannot make Browser expose HTTP/2 frames

...

TL;DR

There are 2 main reasons:

  1. There is no way to force HTTP/2 on browser
    => Because we need a server to support HTTP/2 too! and most of the server now in the internet only support HTTP/1.1

  2. Even we can force HTTP/2 on browser, raw HTTP/2 frames are inaccessible in browsers
    => Browser nowadays supports HTTP/2, but it hides the communication part behind the scene. So it exposes only some small API to HTTP/2.
    gRPC uses HTTP/2, but not a trivial HTTP/2, it leverage a header frame to end the gRPC session (called 'Trailer' header frame).
    And this 'Trailer' header frame has to be accessible by JS, to determine the end of gRPC session along with grpc-status.
    But the Chromium team decided to 'WontFix' due to "the cost of this feature" is not worth it !!


Believe it or not.

I've attached the decision made by Chromium team member here

As I explained previously, the time cost is not a single-cost, but an ongoing resource cost that will be perpetually paid, as every feature will need to consider the interactions with and implications of trailers. Writing the code is, unquestionably, the easy part - reviewing it for correctness, maintaining it for cross-browser interoperability, interacting with the rest of the networking and loading stack are significant and non-trivial costs. As we explained on the issue as well ( https://github.com/whatwg/fetch/issues/34 )
That also discusses security risks. From a product perspective, only supporting it for non-semantic expression is equally not a desirable nor interoperable outcome.
I appreciate your interest, but I think the decision to WontFix is based on a holistic evaluation of the cost of this feature, and leaving it Available for over a year is not a good representation that this has been reviewed, triaged, and actively rejected as something we want to support.

See
bugs.chromium.org/p/chromium/issues/detail?id=691599


Very well, let's try to understand their perspective a bit. We have to get some knowledge about gRPC over HTTP/2.

Here is briefly how gRPC over HTTP/2 works

Let's go

HTTP/2 is an upgraded version of HTTP/1.1

I'll cover only 2 gRPC related parts of HTTP/2

  1. Instead of sending HEADER and DATA in the same packet as HTTP/1.1. HTTP/2 introduces concept of Frames--Header frame and DATA frame. Each frames will be sent on different packet
  2. The connection for HTTP/2 is now support multiplexing, e.g. Client can use the same connection to send data to server, server can send data to client at the same time

There are a lot more in HTTP/2 (I recommend to read more on this blog https://ably.com/topic/http2)


That's HTTP/2

Now, gRPC.

Simple RPC call
ref: https://www.oreilly.com/library/view/grpc-up-and/9781492058328/ch04.html#simple_rpc_message_flow

For a simple RPC call to remote server (Unary RPC, client sends single request to server and server sends single response to client),
Request message will split into 3 frames:

  1. HEADER frame (to start the gRPC channel)
  2. DATA frame (your function parameters, can be in protobuf format)
  3. another DATA frame (to tell the server that client is done sending)

Let's look into a bit at the actual data

  1. HEADER frame (to start the gRPC channel)
HEADERS (flags = END_HEADERS)
:method = POST
:scheme = http
:path = /Service/method
:authority = example.com
te = trailers
grpc-timeout = 1S
content-type = application/grpc
grpc-encoding = gzip
Enter fullscreen mode Exit fullscreen mode
  1. DATA frame (your function parameters, can be in protobuf format)
DATA
010101010111010110 // hahaha it is encoded, how would I be able to read it, but you get it right?, it's just a bunch of alien bytes
Enter fullscreen mode Exit fullscreen mode
  1. DATA frame (to tell the server that client is done sending)
DATA (flags = END_STREAM)
Enter fullscreen mode Exit fullscreen mode

Ok now the communicate is at a state called half-closed specifies the HTTP/2 spec

That state thingy have nothing to do to this blog at all, I just want to show off my knowledge a bit. Haha sorry let's continue.

Then the server starts to process client request. Call the method, get the response.

To response to client, server sends 3 frames (3 frame just to demonstrate a simple gRPC call) back to client:

  1. HEADER frame (to tell client that server now want to send response to client)
  2. DATA frame (to return what ever server wants to return)
  3. HEADER frame (to close the gRPC channel), please pay attention to this, server uses HEADER frame to end the gRPC session, NOT DATA frame as when Client want to end the request sending frame. AND this last HEADER frame they called it Trailers in HTTP/2

Again, let's see the actual data

  1. HEADER frame (to tell client that server now want to send response to client)
HEADERS (flags = END_HEADERS)
:status = 200
grpc-encoding = gzip
content-type = application/grpc
Enter fullscreen mode Exit fullscreen mode
  1. DATA frame (to return what ever server wants to return)
DATA
1000011011100011010 // again it's encoded
Enter fullscreen mode Exit fullscreen mode
  1. HEADER frame (to close the gRPC channel) aka 'Trailers'
HEADERS (flags = END_STREAM, END_HEADERS)
grpc-status = 0  // 0 means OK for gRPC
grpc-message = xxxxxx
Enter fullscreen mode Exit fullscreen mode

That's all, when client receives this last frame (Trailers) it can read this grpc-status to understand the status of the gRPC call.

And JS want to read this Trailers frame but Trailers frame is not accessible in Browser since browser was implemented, even until now.

The problem is, why don't they implement it, right?

I ask the same question, everyone ask the same question, but the answer to that is "the cost of this feature" is not worth it!!


Now they try to introduce another protocol called 'grpc-web' to not always relies on HTTP/2.

YES I'M NOT MAD AT ALL

If you want to see it yourself, please read it here (don't miss last comment): bugs.chromium.org/p/chromium/issues/detail?id=691599

Bye

Top comments (0)