Can tonic-web act as a standalone gRPC-Web reverse proxy for non-tonic backends?
#2787
ContextFor the past few years, my team and I have been building full-stack web apps backed by a C++ gRPC server. To bridge browser HTTP/1.1 requests to gRPC over HTTP/2, we currently use the Golang gRPC Web Proxy. That setup works, but it has platform limitations for us:
I recently started using QueryFrom what I understand, Can In other words, can it be used as a drop-in replacement for the Go gRPC-Web Proxy without requiring the backend server itself to be written in Rust/tonic? |
Replies: 1 comment 1 reply
|
Yes, and I verified it end to end against a non-Rust backend before writing this. tonic-web does not ship a standalone proxy binary, but its translation layer is fully decoupled from tonic services, so about sixty lines of glue turn it into exactly the drop-in you describe, as an embeddable Rust library rather than a process you shell out to, which addresses both your MSVC and Android constraints. The decoupling is visible in the trait bounds. In impl<S, ReqBody, ResBody> Service<Request<ReqBody>> for GrpcWebService<S>
where
S: Service<Request<Body>, Response = Response<ResBody>>,
ReqBody: http_body::Body<Data = bytes::Bytes> + Send + 'static,
ResBody: http_body::Body<Data = bytes::Bytes> + Send + 'static,The inner That forwarder is small. The essential part: #[derive(Clone)]
struct GrpcForward {
client: Client<HttpConnector, TonicBody>, // hyper-util client, http2_only(true)
backend: Authority, // e.g. 127.0.0.1:50051
}
impl tower::Service<Request<TonicBody>> for GrpcForward {
type Response = Response<hyper::body::Incoming>; // Incoming preserves trailers
// poll_ready: Ready; call: rewrite scheme+authority to the backend,
// keep the /package.Service/Method path, client.request(req)
}
let proxy = GrpcWebLayer::new().layer(GrpcForward { client, backend });
// serve with hyper-util auto::Builder (accepts HTTP/1.1 and h2) + TowerToHyperServiceThis compiles against the current workspace with no protoc anywhere, and I ran the full path rather than trusting the types. Backend: a pure Python grpcio server using a generic raw-bytes handler, so no protobuf and no Rust on that side, standing in for your C++ service. Client: curl over HTTP/1.1 posting a handcrafted gRPC-Web frame (0x00 flag, 4-byte length, payload) with Caveats so you can judge fit against grpcwebproxy:
Since the listener is just a tokio task, the same code embeds directly in a |
Yes, and I verified it end to end against a non-Rust backend before writing this. tonic-web does not ship a standalone proxy binary, but its translation layer is fully decoupled from tonic services, so about sixty lines of glue turn it into exactly the drop-in you describe, as an embeddable Rust library rather than a process you shell out to, which addresses both your MSVC and Android constraints.
The decoupling is visible in the trait bounds. In
tonic-web/src/service.rs(v0.14.6, lines 70-76):