httprustactix-webrust-actix

'Access-Control-Allow-Origin' missing using actix-web


Stuck on this problem where I received this error everytime making POST request to my actix-web server.

CORS header 'Access-Control-Allow-Origin' missing

my javascript (VueJs running on localhost:3000) :

let data = //some json data
let xhr = new XMLHttpRequest();
xhr.open("POST", "http://localhost:8080/abc");
xhr.setRequestHeader("Content-Type", "application/json");
xhr.onload = () => {
    console.log(xhr.responseText);
}
xhr.send(JSON.stringify(data));

My Actix_Web server (running on localhost:8080) :

#[actix_web::main]
async fn main() {

    HttpServer::new(move || {
        let cors = Cors::default()
        .allowed_origin("http://localhost:3000/")
        .allowed_methods(vec!["GET", "POST"])
        .allowed_header(actix_web::http::header::ACCEPT)
        .allowed_header(actix_web::http::header::CONTENT_TYPE)
        .max_age(3600);

        App::new()
        .wrap(cors)
        .service(myfunc)
    })
    .bind(("0.0.0.0", 8080))
    .unwrap()
    .run()
    .await
    .unwrap();

}

my cargo.toml dependencies

[dependencies]
actix-web = "4"
actix-cors = "0.6.1"
...

Got any idea?


Solution

  • Okay, so I've done some testing. If you're writing a public API, you probably want to allow all origins. For that you may use the following code:

    HttpServer::new(|| {
        let cors = Cors::default().allow_any_origin().send_wildcard();
    
        App::new().wrap(cors).service(greet)
    })
    

    If you're not writing a public API... well, I'm not sure what they want you to do. I've not figured out how to tell the library to send that header. I guess I will look at the code.

    UPDATE:

    So funny story, this is how you allow specific origins:

    let cors = Cors::default()
        .allowed_origin("localhost:3000")
        .allowed_origin("localhost:2020");
    

    BUT, and oh boy, is that but juicy. The Access-Control-Allow-Origin response header is only set when there is a Origin request header. That header is normally added by the browser in certain cases 1. So I did that (using the Developer tools in the browser). What did I get? "Origin is not allowed to make this request". I set my origin header to localhost:3000. Turns out, the arctix library simply discards that header if no protocol was provided... (e.g. http://) (I assume it discards it, if it deems its format invalid). That internally results in the header being the string "null". Which is, checks notes, not in the list of allowed origins.

    And now the grand finale:

    1. Your origin header needs to be set to (by either you or the browser): "http://localhost:3000".
    2. Your configuration needs to include: .allowed_origin("http://localhost:3000").

    After doing that, the server will happily echo back your origin header in the Access-Control-Allow-Origin header. And it will only send that one.

    I've no idea if any of that is what the standard specifies (or not). I encourage you to read through it, and if it doesn't comply, please open an issue on GitHub. I would do it myself, but I'm done with programming for today.

    Cheers!