最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

rust - Extension middleware not added to fallbacks? - Stack Overflow

programmeradmin1浏览0评论

I have the following simple code:

use std::{net::SocketAddr, path::Path};

use axum::{extract::{ConnectInfo, Request, State}, middleware::Next, response::{Html, IntoResponse, Response}, routing::{get, get_service}, Extension};
use tower_http::services::ServeDir;

#[derive(Clone, Debug)]
struct AppState {
    something: String
}

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

    let state = AppState {
        something: "Hello world!".to_string()
    };

    let app = axum::Router::new()
        .route("/", get(home_get))
        .nest_service("/assets", get_service(ServeDir::new(Path::new("assets"))))
        .fallback(get(home_get).with_state(state.clone()))
        .route_layer(axum::middleware::from_fn_with_state(state.clone(),info_middleware))
        .with_state(state);

    let listener = tokio::net::TcpListener::bind(":::7070").await.unwrap();
    axum::serve(listener, app.into_make_service_with_connect_info::<SocketAddr>()).await.unwrap();
}

async fn home_get(state: State<AppState>, connection_info: Extension<MyConnectionInfo>) -> Response {
    Html(format!("{} You called from: {}",state.something,connection_info.ip)).into_response()
}

#[derive(Clone, Debug)]
pub struct MyConnectionInfo {
    pub ip: String
}

pub async fn info_middleware(addr: ConnectInfo<SocketAddr>, mut request: Request, next: Next) -> Response {
    request.extensions_mut().insert(MyConnectionInfo {ip: addr.to_string()});
    next.run(request).await
}

In a real world example, my state would contain the database pool from sqlx and the info_middleware would do things like ensure token is valid, extract IP address, User agent etc. and make it available to all handlers.

For routing, basically:

  1. "/" is to take user to home_get
  2. "/assets/favicon.ico" serves the favicon file in the assets folder, and
  3. any other routes is to fallback to home_get.

1 and 2 work well. 3 does not.

For example, "/submit" fails with below 500 Internal error:

Missing request extension: Extension of type `fallbackdemo::MyConnectionInfo` was not found. Perhaps you fot to add it? See `axum::Extension`.

I think this is because the Extension middleware isn't accessible to fallbacks?

How to make it work? Or some workaround (other than having to specify every single fallback route manually)?

I have the following simple code:

use std::{net::SocketAddr, path::Path};

use axum::{extract::{ConnectInfo, Request, State}, middleware::Next, response::{Html, IntoResponse, Response}, routing::{get, get_service}, Extension};
use tower_http::services::ServeDir;

#[derive(Clone, Debug)]
struct AppState {
    something: String
}

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

    let state = AppState {
        something: "Hello world!".to_string()
    };

    let app = axum::Router::new()
        .route("/", get(home_get))
        .nest_service("/assets", get_service(ServeDir::new(Path::new("assets"))))
        .fallback(get(home_get).with_state(state.clone()))
        .route_layer(axum::middleware::from_fn_with_state(state.clone(),info_middleware))
        .with_state(state);

    let listener = tokio::net::TcpListener::bind(":::7070").await.unwrap();
    axum::serve(listener, app.into_make_service_with_connect_info::<SocketAddr>()).await.unwrap();
}

async fn home_get(state: State<AppState>, connection_info: Extension<MyConnectionInfo>) -> Response {
    Html(format!("{} You called from: {}",state.something,connection_info.ip)).into_response()
}

#[derive(Clone, Debug)]
pub struct MyConnectionInfo {
    pub ip: String
}

pub async fn info_middleware(addr: ConnectInfo<SocketAddr>, mut request: Request, next: Next) -> Response {
    request.extensions_mut().insert(MyConnectionInfo {ip: addr.to_string()});
    next.run(request).await
}

In a real world example, my state would contain the database pool from sqlx and the info_middleware would do things like ensure token is valid, extract IP address, User agent etc. and make it available to all handlers.

For routing, basically:

  1. "/" is to take user to home_get
  2. "/assets/favicon.ico" serves the favicon file in the assets folder, and
  3. any other routes is to fallback to home_get.

1 and 2 work well. 3 does not.

For example, "/submit" fails with below 500 Internal error:

Missing request extension: Extension of type `fallbackdemo::MyConnectionInfo` was not found. Perhaps you fot to add it? See `axum::Extension`.

I think this is because the Extension middleware isn't accessible to fallbacks?

How to make it work? Or some workaround (other than having to specify every single fallback route manually)?

Share Improve this question edited Jan 19 at 23:13 Ken White 126k15 gold badges236 silver badges464 bronze badges asked Jan 19 at 21:56 sudoExclamationExclamationsudoExclamationExclamation 8,81410 gold badges51 silver badges119 bronze badges
Add a comment  | 

1 Answer 1

Reset to default 1

The reason it doesn't work is because you are using route_layer. It only applies to a specific route, as explained here: https://docs.rs/axum/latest/axum/struct.Router.html#method.route_layer

use layer instead and it will work just fine:

use std::{net::SocketAddr, path::Path};

use axum::{
    extract::{ConnectInfo, Request, State},
    middleware::Next,
    response::{Html, IntoResponse, Response},
    routing::{get, get_service},
    Extension,
};
use tower_http::services::ServeDir;

#[derive(Clone, Debug)]
struct AppState {
    something: String,
}

#[tokio::main]
async fn main() {
    let state = AppState {
        something: String::from("Hello World!"),
    };

    let app = axum::Router::new()
        .route("/", get(home_get))
        .nest_service("/assets", get_service(ServeDir::new(Path::new("assets"))))
        .fallback(get(home_get).with_state(state.clone()))
        .layer(axum::middleware::from_fn_with_state(
            state.clone(),
            info_middleware,
        ))
        .with_state(state);
    let listener = tokio::net::TcpListener::bind(":::7070").await.unwrap();
    axum::serve(
        listener,
        app.into_make_service_with_connect_info::<SocketAddr>(),
    )
    .await
    .unwrap();
}

async fn home_get(
    state: State<AppState>,
    connection_info: Extension<MyConnectionInfo>,
) -> impl IntoResponse {
    Html(format!(
        "{} You called from: {}",
        state.something, connection_info.ip
    ))
}

#[derive(Clone, Debug)]
struct MyConnectionInfo {
    pub ip: String,
}
pub async fn info_middleware(
    addr: ConnectInfo<SocketAddr>,
    mut request: Request,
    next: Next,
) -> Response {
    request.extensions_mut().insert(MyConnectionInfo {
        ip: addr.to_string(),
    });
    next.run(request).await
}

发布评论

评论列表(0)

  1. 暂无评论