Reputation: 3892
I'm trying to make a web app with React in the frontend and Rust as the backend. I thought I'd use gRPC through the Tonic crate, to communicate between the front and back end. But I'm getting the error:
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://localhost:50051/helloworld.Users/GetUsers. (Reason: CORS header ‘Access-Control-Allow-Origin’ missing). Status code: 200.
Any ideas how I could add the CORS header with Tonic?
Upvotes: 1
Views: 3146
Reputation: 159
The tonic_web
api has changed since the accepted answer. Config
has been removed, so CORS is no longer configurable using tonic_web directly, as apparently the implementation was not standards compliant.
Instead you need to add two layers - GrpcWebLayer
to handle the grpc-web stuff, and CorsLayer
from the tower-http
crate to enable CORS.
Here's a sample application using tonic, tonic_web and CORS.
/Cargo.toml
[package]
name = "tonic_cors_example"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
tonic = "0.8.3"
tonic-web = "0.5.0"
prost = "0.11.3"
tokio = { version = "1.22.0", features = ["macros", "rt-multi-thread"] }
tower-http = { version = "0.3.5", features = ["cors"] }
http = "0.2.8"
[build-dependencies]
tonic-build = "0.8.4"
/build.rs
fn main() -> Result<(), Box<dyn std::error::Error>> {
tonic_build::compile_protos("proto/helloworld.proto")?;
Ok(())
}
/proto/helloworld.proto
syntax = "proto3";
package helloworld;
service Greeter {
// Our SayHello rpc accepts HelloRequests and returns HelloReplies
rpc SayHello (HelloRequest) returns (HelloReply);
}
message HelloRequest {
// Request message contains the name to be greeted
string name = 1;
}
message HelloReply {
// Reply contains the greeting message
string message = 1;
}
/src/main.rs
use tonic::{transport::Server, Request, Response, Status};
use hello_world::greeter_server::{Greeter, GreeterServer};
use hello_world::{HelloReply, HelloRequest};
use tonic_web::GrpcWebLayer;
use tower_http::cors::{Any, CorsLayer};
use http::Method;
pub mod hello_world {
tonic::include_proto!("helloworld"); // The string specified here must match the proto package name
}
#[derive(Debug, Default)]
pub struct MyGreeter {}
#[tonic::async_trait]
impl Greeter for MyGreeter {
async fn say_hello(
&self,
request: Request<HelloRequest>, // Accept request of type HelloRequest
) -> Result<Response<HelloReply>, Status> { // Return an instance of type HelloReply
println!("Got a request from: {:?}", request);
let reply = hello_world::HelloReply {
message: format!("Hello {}!", request.into_inner().name).into(), // We must use .into_inner() as the fields of gRPC requests and responses are private
};
Ok(Response::new(reply)) // Send back our formatted greeting
}
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let addr = "[::1]:3000".parse()?;
let greeter = GreeterServer::new(MyGreeter::default());
println!("GreeterServer listening on {}", addr);
let cors = CorsLayer::new()
// allow any headers
.allow_headers(Any)
// allow `POST` when accessing the resource
.allow_methods([Method::POST])
// allow requests from below origins
.allow_origin(["http://localhost:5000".parse()?, "https://localhost:5001".parse()?]);
Server::builder()
.accept_http1(true)
.layer(cors)
.layer(GrpcWebLayer::new())
.add_service(greeter)
.serve(addr)
.await?;
Ok(())
}
Upvotes: 4
Reputation: 4017
grpc-web interoperability can be achieved through tonic-project crate tonic-web
:
#[derive(Default)]
struct MyUsers;
#[tonic::async_trait]
impl UsersServer for MyUsers {
// ...
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let my_service = MyUsers::default() // .. standard way to create tonic-service
let service = tonic_web::config()
.allow_origins(vec!["http://example.com"])
.enable(UsersServerServer::new(my_service));
Server::builder()
.accept_http1(true)
.add_service(service)
.server("[::1]:50051".parse().unwrap()).await?;
Ok(())
}
See https://github.com/hyperium/tonic/pull/455 and https://docs.rs/tonic-web/latest/tonic_web/
Upvotes: 3