To handle CORS in Rust, you must explicitly configure your web server to send the correct Access-Control-Allow-Origin and related headers in response to browser requests. The most robust approach is to use the cors crate with a framework like actix-web or axum, which automatically handles preflight OPTIONS requests and validates allowed origins, methods, and headers.
For actix-web, add the actix-cors dependency and wrap your app with the Cors middleware. This middleware handles the complex logic of preflight checks and header injection automatically.
use actix_web::{web, App, HttpServer, HttpResponse};
use actix_cors::Cors;
async fn index() -> HttpResponse {
HttpResponse::Ok().body("Hello CORS!")
}
#[actix_web::main]
async fn main() -> std::io::Result<()> {
let cors = Cors::default()
.allow_any_origin() // Use .allowed_origin("https://example.com") in production
.allow_any_method()
.allow_any_header()
.max_age(3600);
HttpServer::new(move || {
App::new()
.wrap(cors)
.route("/", web::get().to(index))
})
.bind("127.0.0.1:8080")?
.run()
.await
}
If you are using axum, the tower-http crate provides the cors middleware. You configure it similarly by defining allowed origins and methods, then apply it as a layer to your router.
use axum::{routing::get, Router};
use tower_http::cors::{Any, CorsLayer};
async fn hello() -> &'static str {
"Hello CORS!"
}
#[tokio::main]
async fn main() {
let cors = CorsLayer::new()
.allow_origin(Any) // Restrict to specific origins in production
.allow_methods(Any)
.allow_headers(Any);
let app = Router::new()
.route("/", get(hello))
.layer(cors);
let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await.unwrap();
axum::serve(listener, app).await.unwrap();
}
In production, never use allow_any_origin() or Any for origins unless your API is truly public. Instead, specify the exact domain of your frontend application (e.g., https://myapp.com) to prevent cross-site request forgery (CSRF) and data leakage. Also, ensure you explicitly allow the necessary HTTP methods (GET, POST, etc.) and headers (like Content-Type or Authorization) required by your client. If you are building a custom server without a framework, you must manually inspect the Origin header in incoming requests and return the appropriate Access-Control-Allow-Origin header, while also returning a 204 No Content response for OPTIONS requests to satisfy preflight checks.