扩展中间件未添加到后备中?

问题描述 投票:0回答:1

我有以下简单的代码:

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
}

在现实世界的示例中,我的

state
将包含来自
sqlx
的数据库池,并且
info_middleware
会执行诸如确保
token
有效、提取 IP 地址、用户代理等操作,并将其提供给所有人处理程序。

对于路由,基本上:

  1. "/"
    是将用户带到
    home_get
  2. "/assets/favicon.ico"
    提供资源文件夹中的图标文件,并且
  3. 任何其他路线都可以回退到
    home_get

1 和 2 效果很好。 3 没有。

例如,

"/submit"
失败,内部错误低于 500:

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

我认为这是因为扩展中间件无法进行后备访问?

如何让它发挥作用?或者一些解决方法(除了必须手动指定每个后备路由之外)?

rust rust-axum
1个回答
0
投票

它不起作用的原因是因为你正在使用

route_layer
。它仅适用于特定路线,如下所述:https://docs.rs/axum/latest/axum/struct.Router.html#method.route_layer

使用

layer
来代替,它会正常工作:

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
}

© www.soinside.com 2019 - 2024. All rights reserved.