Grpc Web

Lets a browser call a gRPC backend

Versions marked “overview” do not contain this page. Selecting one opens that version’s documentation overview.

Category: Setup-dependent integration
Task: Lets a browser call a gRPC backend

Prerequisites: The external service, credentials, or certificates referenced by this configuration.

Run it: Use ghcr.io/praxis-proxy/praxis:0.7.2 and follow the first reverse-proxy tutorial to mount and start the configuration.

This configuration comes from the selected release. The example has not been run here; external services are not bundled.

Download the source file.

# gRPC-Web to gRPC Translation
#
# Lets a browser call a gRPC backend. Browsers cannot speak gRPC: they
# have no access to HTTP/2 trailers, which is where a call's status
# lives. gRPC-Web keeps the same length-prefixed framing but moves the
# trailers into the body as one final frame, and optionally base64-
# encodes the whole stream so it survives an XMLHttpRequest.
#
# This filter rewrites the request's content-type to native gRPC
# (base64-decoding the body first for the -text variant), rewrites the
# response's content-type back, and converts the upstream response
# trailers into the trailer frame the browser expects. A Trailers-Only
# response needs no frame: it carries the status in its header block,
# which is where a gRPC-Web client looks for it.
#
# Requires an HTTP/2 upstream: trailers exist on no other leg, so there
# would be nothing to translate. Non-gRPC-Web requests pass through
# untouched.
#
listeners:
  - name: grpc-web
    address: "127.0.0.1:8080"
    protocol: http
    filter_chains: [main]

filter_chains:
  - name: main
    filters:
      - filter: grpc_web
        encodings:
          # application/grpc-web[+codec] — raw frames.
          binary: true
          # application/grpc-web-text[+codec] — base64 frames. Request
          # bodies are buffered to decode them, so scope this chain to
          # gRPC-Web routes if that cost matters.
          text: true
        # Ceiling for buffering a base64 request body.
        max_buffer_bytes: 10485760 # 10 MiB
        # synthesize: append grpc-status 2 (UNKNOWN) when the upstream
        #   ends the stream without a status, so the browser sees an
        #   explicit failure rather than a parse error.
        # passthrough: forward the body unchanged.
        on_missing_trailers: synthesize

      - filter: router
        routes:
          - path_prefix: "/"
            cluster: grpc-backend

      - filter: load_balancer
        clusters:
          - name: grpc-backend
            endpoints:
              - "127.0.0.1:50051"
            http:
              # Required: the trailers this filter translates exist only
              # on an HTTP/2 leg.
              version: h2

insecure_options:
  allow_private_endpoints: true # example proxies to a local backend