Working with gRPC-Web

1. Understanding gRPC-Web Protocol

ConceptDetail
NeedBrowsers can't speak HTTP/2 trailers natively
SolutionHTTP/1.1 or HTTP/2 wire with status in body
ProxyEnvoy or in-process middleware translates to gRPC
StreamingServer streaming supported; bidi requires WebSocket extension

2. Installing gRPC-Web Package

Example: npm install

npm install grpc-web google-protobuf
npm install -D protoc-gen-grpc-web ts-proto

3. Configuring grpcwebtext Mode

ModeDetail
grpcwebtext (default)Base64-encoded; works without proxy CORS adjustments
Larger payload~33% overhead

4. Configuring grpcweb Mode

ModeDetail
grpcweb (binary)Raw protobuf; smaller, faster
Requires CORSAllow application/grpc-web+proto content type

5. Setting Up Envoy Proxy

Example: Envoy filter snippet

http_filters:
  - name: envoy.filters.http.grpc_web
  - name: envoy.filters.http.cors
  - name: envoy.filters.http.router
route_config:
  virtual_hosts:
    - name: backend
      domains: ["*"]
      cors:
        allow_origin_string_match: [{prefix: "*"}]
        allow_methods: GET,POST,OPTIONS
        allow_headers: keep-alive,user-agent,cache-control,content-type,content-transfer-encoding,custom-header-1,x-accept-content-transfer-encoding,x-accept-response-streaming,x-user-agent,x-grpc-web,grpc-timeout
        expose_headers: grpc-status,grpc-message

6. Generating JavaScript Client

Example: protoc gen js + grpc-web

protoc -I proto \
  --js_out=import_style=commonjs:gen/web \
  --grpc-web_out=import_style=typescript,mode=grpcweb:gen/web \
  proto/user/v1/user.proto

7. Creating Browser Client

Example: TypeScript client call

import { UserServiceClient } from "./gen/web/UserServiceClientPb";
import { GetUserRequest } from "./gen/web/user_pb";

const client = new UserServiceClient("https://api.example.com");
const req = new GetUserRequest();
req.setId("u1");
const user = await client.getUser(req, { authorization: "Bearer " + token });

8. Handling CORS

HeaderPurpose
Access-Control-Allow-OriginAllowed origins
Access-Control-Expose-HeadersMust include grpc-status, grpc-message
PreflightHandle OPTIONS with appropriate methods/headers

9. Using Unary Calls in Browser

APIDetail
Promise-basedawait client.method(req, metadata)
Callbackclient.method(req, md, (err, res) => {})

10. Using Server Streaming in Browser

Example: Server streaming

const stream = client.listEvents(req, {});
stream.on("data", (evt) => console.log(evt.toObject()));
stream.on("status", (s) => console.log("code", s.code));
stream.on("end", () => console.log("done"));
Note: Client streaming and bidi are NOT supported by gRPC-Web spec. Use Connect-Web or WebTransport for these patterns.