Axum router rejecting CORS OPTIONS preflight with 405 even with CorsLayer

6.8k views Asked by At

Before a fetch is sent, the browser will send a request method OPTIONS to confirm that the API will accept the request from a script with a particular origin.

Chrome shows that the my Axum server is rejecting my client's request with 405. My router looks something like this:

let app = Router::new()
    .layer(TraceLayer::new_for_http())
    .layer(CorsLayer::permissive())
    .route("/api", post(server));

Router::layer says All requests to the router will be processed by the layer’s corresponding middleware. but I'm not sure its doing its job.

2

There are 2 answers

1
Alister Lee On BEST ANSWER

The .layer() function is a builder so returns a new Router, with the inner routers wrapped. The route /api will be tested first and be rejected 405 because only request method POST is supported - not OPTIONS.

In summary, you need your CorsLayer "outside" your route so it can answer OPTIONS requests.

Note the example in the documentation:

// All requests to `first_handler` and `second_handler` will be sent through
// `ConcurrencyLimit`
let app = Router::new().route("/", get(first_handler))
    .route("/foo", get(second_handler))
    .layer(ConcurrencyLimitLayer::new(64))
    // Request to `GET /bar` will go directly to `third_handler` and
    // wont be sent through `ConcurrencyLimit`
    .route("/bar", get(third_handler));

By the way, your TraceLayer is not tracing your API calls for the same reason!

Try this, and you'll see the OPTIONS request logged, and the POST should hit your server:

let app = Router::new()
    .route("/api", post(server))
    .layer(CorsLayer::permissive())
    .layer(TraceLayer::new_for_http());
0
Sunding Wei On

Thanks, that solved the cross origin issue for Chrome

let app = Router::new()
    .route("/api", post(server))
    .layer(CorsLayer::permissive()) <----- PUT IT HERE
    .layer(TraceLayer::new_for_http());