mirror of https://github.com/fafhrd91/actix-web
docs: clarify cross-level middleware ordering between App and Scope
The existing docs stated middleware executes in 'opposite order as registration' without clarifying this only applies within a single level (App, Scope, or Resource). When middleware is registered at both the App level and a Scope level, App middleware *always* runs first because it structurally wraps the entire request router. Scope middleware cannot bypass or run before App middleware. Changes: - Qualify the 'opposite order' statement in middleware/mod.rs to note it applies within a single level only - Add a new 'Cross-Level Middleware Ordering' section with an ASCII diagram, explanation, and a code example showing the recommended per-scope pattern - Add a '# Middleware Ordering' note to App::wrap pointing to the new section Closes: https://github.com/actix/actix-web/issues/2993
This commit is contained in:
parent
15cfc03878
commit
af844c6d08
|
|
@ -326,6 +326,20 @@ where
|
|||
/// Middleware can be applied similarly to individual `Scope`s and `Resource`s.
|
||||
/// See [`Scope::wrap`](crate::Scope::wrap) and [`Resource::wrap`].
|
||||
///
|
||||
/// # Middleware Ordering
|
||||
///
|
||||
/// App-level middleware wraps the entire request router and **always executes before** any
|
||||
/// [`Scope`](crate::Scope)-level or [`Resource`]-level middleware, regardless of the order in
|
||||
/// which services are registered on the builder. Scope middleware cannot bypass or run before
|
||||
/// App middleware.
|
||||
///
|
||||
/// If you need certain routes to skip a middleware, apply that middleware at the
|
||||
/// [`Scope`](crate::Scope) level instead of the `App` level.
|
||||
///
|
||||
/// For more info on middleware ordering, see the
|
||||
/// [Cross-Level Middleware Ordering](crate::middleware#cross-level-middleware-ordering)
|
||||
/// section.
|
||||
///
|
||||
/// For more info on middleware take a look at the [`middleware` module][crate::middleware].
|
||||
///
|
||||
/// # Examples
|
||||
|
|
|
|||
|
|
@ -15,7 +15,10 @@
|
|||
//! - Access external services (e.g., [sessions](https://docs.rs/actix-session), etc.)
|
||||
//!
|
||||
//! Middleware is registered for each [`App`], [`Scope`](crate::Scope), or
|
||||
//! [`Resource`](crate::Resource) and executed in opposite order as registration.
|
||||
//! [`Resource`](crate::Resource) and executed in opposite order as registration. Note that this
|
||||
//! reverse ordering applies _within_ a single level (`App`, `Scope`, or `Resource`). When
|
||||
//! middleware exists at multiple levels, App-level middleware always runs first. See
|
||||
//! [Cross-Level Middleware Ordering](#cross-level-middleware-ordering) for details.
|
||||
//!
|
||||
//! # Simple Middleware
|
||||
//!
|
||||
|
|
@ -120,6 +123,62 @@
|
|||
//! middleware are run in reverse order for [`App`] _and then_ in reverse order for the wrapped
|
||||
//! service.
|
||||
//!
|
||||
//! # Cross-Level Middleware Ordering
|
||||
//!
|
||||
//! When middleware is registered on _both_ an [`App`] and a [`Scope`](crate::Scope) (or
|
||||
//! [`Resource`](crate::Resource)), the App-level middleware **always** runs before the
|
||||
//! Scope/Resource-level middleware. This is because App-level middleware wraps the entire request
|
||||
//! router, and routing to a specific scope or resource happens _inside_ that middleware chain.
|
||||
//!
|
||||
//! ```plain
|
||||
//! Request
|
||||
//! ⭣
|
||||
//! ╭──────────────────────┼──────╮
|
||||
//! │ App Middleware │ │
|
||||
//! │ ╭────────────────────┼─────╮│
|
||||
//! │ │ Router │ ││
|
||||
//! │ │ ╭─────────────┼────╮││
|
||||
//! │ │ │ Scope MW │ │││
|
||||
//! │ │ │ ╭───────────┼───╮│││
|
||||
//! │ │ │ │ Resource │ ││││
|
||||
//! │ │ │ │ MW │ ││││
|
||||
//! │ │ │ │ ╭─────────┼──╮││││
|
||||
//! │ │ │ │ │ Handler │ │││││
|
||||
//! │ │ │ │ ╰─────────┼──╯││││
|
||||
//! │ │ │ ╰───────────┼───╯│││
|
||||
//! │ │ ╰─────────────┼────╯││
|
||||
//! │ ╰────────────────────┼─────╯│
|
||||
//! ╰──────────────────────┼──────╯
|
||||
//! ⭣
|
||||
//! Response
|
||||
//! ```
|
||||
//!
|
||||
//! This means that a middleware applied to a [`Scope`](crate::Scope) **cannot** bypass or run
|
||||
//! before middleware applied to the enclosing [`App`]. For example, if authentication middleware
|
||||
//! is registered on `App`, a "bypass auth" middleware on a scope will not work because the App
|
||||
//! auth middleware has already executed by the time routing reaches that scope.
|
||||
//!
|
||||
//! If you need different middleware behavior for different groups of routes, apply middleware at
|
||||
//! the scope level rather than the app level:
|
||||
//!
|
||||
//! ```
|
||||
//! use actix_web::{web, middleware, App};
|
||||
//!
|
||||
//! // Instead of applying auth middleware at the App level and trying
|
||||
//! // to bypass it on certain scopes, apply it per-scope:
|
||||
//! let app = App::new()
|
||||
//! .service(
|
||||
//! web::scope("/api")
|
||||
//! .wrap(middleware::DefaultHeaders::new()) // e.g., auth middleware
|
||||
//! // ... api routes
|
||||
//! )
|
||||
//! .service(
|
||||
//! web::scope("/public")
|
||||
//! // no auth middleware here
|
||||
//! // ... public routes
|
||||
//! );
|
||||
//! ```
|
||||
//!
|
||||
//! # Middleware Traits
|
||||
//!
|
||||
//! ## `Transform<S, Req>`
|
||||
|
|
|
|||
Loading…
Reference in New Issue