rustcorsactix-web

CORS actix-web Access to XMLHttpRequest has been blocked by CORS policy


I have an actix-web backend and a react frontend. I started getting this cors error. It was initially easy to resolve by adding

       let cors = Cors::default()
           .allowed_origin("http://localhost:3000")
           .allowed_origin("http://10.0.0.77:3000")
           .allowed_methods(vec!["GET", "POST", "PUT", "DELETE"])
           .allowed_headers(vec![header::AUTHORIZATION, header::ACCEPT])
           .allowed_header(header::CONTENT_TYPE)
           .max_age(3600);
          ...
          ...
          .wrap(cors)

But the error started happening again.

It allows me to send requests to my login route, but not to my other routes.

I tried the other solutions I saw online, ex: adding

.wrap(Cors::permissive()) 

But it didn't change a thing, as if it had no effect at all.

my main()

#[actix_web::main]
async fn main() -> std::io::Result<()> {
   dotenv().ok();
   std::env::set_var("RUST_LOG", "actix_web=info");
   env_logger::init();
   
   let pool: Pool<Postgres> = PgPoolOptions::new()
       .max_connections(5)
       .connect(&std::env::var("LOCAL_DATABASE_URL").expect("DATABASE_URL must be set"))
       .await
       .expect("Error building a connection pool");

       HttpServer::new(move || {
           App::new()
           .wrap(Cors::permissive())
               .app_data(Data::new(AppState{db:pool.clone()}))
               .wrap(Logger::default())
               .wrap(AuthMiddleware)
               .route("/signup", web::post().to(signup))
               .route("/login", web::post().to(login))
               .route("/recruit", web::post().to(recruit))
               .route("/get_recruiter", web::post().to(recruiter))
   })
   .bind("127.0.0.1:8080")?
   .workers(10)
   .run()
   .await
}

The react code

  useEffect(() => {
    const fetchRecruiterData = async () => {
      const token = localStorage.getItem('authToken');
      if (!token || !user) return;

      try {
        const response = await axios.post('http://127.0.0.1:8080/get_recruiter',
          {filter: "id", value: user.reporter_id},
          {headers: {Authorization: `${token}`}}
        );
        setRecruiterData(response.data);
      } catch (error) {
        console.error('Error fetching recruiter data:', error);
      }
    };

    fetchRecruiterData();
  }, [user]);

And I get this error

Access to XMLHttpRequest at 'http://127.0.0.1:8080/get_recruiter' 
from origin 'http://10.0.0.77:3000' has been blocked by CORS policy:
Response to preflight request doesn't pass access control check:
No 'Access-Control-Allow-Origin' header is present on the requested resource.

No solution I saw online solved it, I can't figure out what is wrong, especially why Cors::permissive() doesn't seem to work.

Do you have any idea what could it be?


Solution

  • Most Rust frameworks process middleware in the reverse order that they are registered. The same is true for actix.

    This means your Auth and Logger middleware will try to process the request first before the CORS layer can respond with the appropriate response to handle the CORS request. Handling the Logger first should not be a problem since it won't handle the request. But I suspect your Auth middleware might try to respond to requests and therefore won't handle the CORS requests correctly.

    So just register the CORS layer after the Auth layer:

    App::new()
        .app_data(Data::new(AppState{db:pool.clone()}))
        .wrap(AuthMiddleware)
        .wrap(Cors::permissive())
        .wrap(Logger::default())
        .route("/signup", web::post().to(signup))
        .route("/login", web::post().to(login))
        .route("/recruit", web::post().to(recruit))
        .route("/get_recruiter", web::post().to(recruiter))