You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Axum中间件如何获取并修改Extensions中的ServiceConfig对象

问题描述

在Rust Axum应用中,创建Router时注入了Extension<ServiceConfig>,但jwt_validator中间件始终无法获取该对象,会进入错误分支返回500状态码;而后续请求处理handler却能正常读取这个配置。需要实现中间件对ServiceConfig的获取、修改,并传递给后续handler。


相关代码

路由创建代码

pub fn create_routes(sc: &ServiceConfig) -> Router {
    let api_routes = Router::new().nest("/", create_workflow_router());

    let router = Router::new()
        .route("/", get(welcome))
        .nest("/api", api_routes)
        .layer(Extension(sc.clone()))
        .layer(from_fn(jwt_validator))
        .layer(ServiceBuilder::new().layer(TraceLayer::new_for_http()));

    router
}

中间件代码

pub async fn jwt_validator(
    req: Request<axum::body::Body>,
    next: Next,
) -> Result<Response, StatusCode> {
      // 尝试从请求扩展中获取ServiceConfig
    let sc = if let Some(Extension(sc)) = req.extensions().get::<Extension<ServiceConfig>>() {
        sc.clone()
    } else {
        trace!("ServiceConfig not found in extensions.");
        return Err(StatusCode::INTERNAL_SERVER_ERROR);
    };

    println!("SC: {:?}", sc);

    return Ok(next.run(req).await);
}

请求处理handler代码

pub async fn get_workflows(
    Query(params): Query<WorkflowQueryParams>,
    Extension(sc): Extension<ServiceConfig>,
) -> impl IntoResponse {
    println!("SC: {:?}", sc);
    Json("Hello")
}

运行日志

错误日志(中间件触发500)

[2024-10-01T06:02:35Z TRACE axum::serve] connection 127.0.0.1:34734 accepted
[2024-10-01T06:02:35Z DEBUG tower_http::trace::make_span] request; method=GET uri=/api/v1/workflows version=HTTP/1.1
[2024-10-01T06:02:35Z TRACE tracing::span::active] -> request;
[2024-10-01T06:02:35Z DEBUG tower_http::trace::on_request] started processing request
[2024-10-01T06:02:35Z TRACE tracing::span::active] <- request;
[2024-10-01T06:02:35Z TRACE tracing::span::active] -> request;
[2024-10-01T06:02:35Z TRACE workflow_svc::middlewares::jwt_validator] ServiceConfig not found in extensions.
[2024-10-01T06:02:35Z DEBUG tower_http::trace::on_response] finished processing request latency=0 ms status=500
[2024-10-01T06:02:35Z ERROR tower_http::trace::on_failure] response failed classification=Status code: 500 Internal Server Error latency=0 ms
[2024-10-01T06:02:35Z TRACE tracing::span::active] <- request;
[2024-10-01T06:02:35Z TRACE tracing::span] -- request;
[2024-10-01T06:02:35Z TRACE tracing::span] -- request;

正常日志(注释中间件错误分支后)

[2024-10-01T06:09:04Z TRACE axum::serve] connection 127.0.0.1:38964 accepted
[2024-10-01T06:09:04Z DEBUG tower_http::trace::make_span] request; method=GET uri=/api/v1/workflows version=HTTP/1.1
[2024-10-01T06:09:04Z TRACE tracing::span::active] -> request;
[2024-10-01T06:09:04Z DEBUG tower_http::trace::on_request] started processing request
[2024-10-01T06:09:04Z TRACE tracing::span::active] <- request;
[2024-10-01T06:09:04Z TRACE tracing::span::active] -> request;
SC: ServiceConfig { auth_enabled: false, jwt_secret: None, host: "localhost", port: 4001, dbc: SqlxPostgresPoolConnection }
[2024-10-01T06:09:04Z DEBUG tower_http::trace::on_response] finished processing request latency=0 ms status=200
[2024-10-01T06:09:04Z TRACE tracing::span::active] <- request;
[2024-10-01T06:09:04Z TRACE tracing::span] -- request;
[2024-10-01T06:09:04Z TRACE tracing::span::active] -> request;
[2024-10-01T06:09:04Z TRACE tracing::span::active] <- request;
[2024-10-01T06:09:04Z TRACE tracing::span] -- request;
[2024-10-01T06:09:04Z TRACE axum::serve] connection 127.0.0.1:38964 closed

解决方案

1. 修复Layer执行顺序问题

Axum的Layer是栈式执行,后添加的Layer会先处理请求。你当前的代码中,Extension Layer先于中间件添加,导致中间件执行时,配置还未被注入到请求扩展中。

调整Layer顺序,将Extension放在中间件之后添加,确保配置先被注入,再执行中间件:

pub fn create_routes(sc: &ServiceConfig) -> Router {
    let api_routes = Router::new().nest("/", create_workflow_router());

    let router = Router::new()
        .route("/", get(welcome))
        .nest("/api", api_routes)
        .layer(from_fn(jwt_validator)) // 先添加中间件
        .layer(Extension(sc.clone()))  // 后添加配置扩展,确保先注入配置
        .layer(ServiceBuilder::new().layer(TraceLayer::new_for_http()));

    router
}

2. 修正中间件中配置的获取方式

请求扩展中存储的是ServiceConfig实例,而非Extension<ServiceConfig>包装器,直接获取对应类型即可:

pub async fn jwt_validator(
    mut req: Request<axum::body::Body>,
    next: Next,
) -> Result<Response, StatusCode> {
    // 正确获取ServiceConfig
    let mut sc = req.extensions()
        .get::<ServiceConfig>()
        .cloned()
        .ok_or_else(|| {
            trace!("ServiceConfig not found in extensions.");
            StatusCode::INTERNAL_SERVER_ERROR
        })?;

    println!("Original SC: {:?}", sc);
    Ok(next.run(req).await)
}

3. 修改配置并传递给后续handler

如果需要修改配置,可移除原有实例并插入修改后的版本,后续handler会读取到更新后的配置:

pub async fn jwt_validator(
    mut req: Request<axum::body::Body>,
    next: Next,
) -> Result<Response, StatusCode> {
    // 获取并克隆原配置
    let mut sc = req.extensions()
        .get::<ServiceConfig>()
        .cloned()
        .ok_or(StatusCode::INTERNAL_SERVER_ERROR)?;

    // 修改配置示例
    sc.auth_enabled = true;
    sc.jwt_secret = Some("updated_secret".to_string());

    // 替换请求扩展中的配置
    req.extensions().remove::<ServiceConfig>();
    req.extensions().insert(sc);

    println!("Modified SC: {:?}", req.extensions().get::<ServiceConfig>().unwrap());
    Ok(next.run(req).await)
}

内容的提问来源于stack exchange,提问作者Mopparthy Ravindranath

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.17 15:55:53