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

如何在使用tower::service_fn的Axum route_service处理器中提取路径参数?

可以提取路径参数,解决方案如下

你可以通过Axum存储在Request扩展中的RouteParts来提取路径参数,无需改动原有的错误处理逻辑,具体实现方式如下:

修改后的完整代码

use axum::{
    extract::Json,
    http::{Request, Response, StatusCode, Method},
    routing::{RouteParts, Router},
    error_handling::HandleError,
};
use reqwest::{Error as ReqwestError, ErrorKind, Client};
use serde_json::Value;
use tower_http::cors::{Any, CorsLayer};
use dotenv::dotenv;

async fn get_person(person_id: String) -> Result<Json<Value>, ReqwestError> {
    let request_url = format!("https://swapi.dev/api/people/{}", person_id);
    let response = reqwest::get(request_url).await?;
    
    if response.status().is_success() {
        let json = response.json::<Value>().await?;
        Ok(Json(json))
    } else {
        Err(response.error_for_status().unwrap_err())
    }
}

#[tokio::main]
async fn main() {
    dotenv().ok();
    let client = Client::new();

    let cors = CorsLayer::new()
        .allow_methods([Method::GET])
        .allow_origin(Any);

    let faillible_person_service = tower::service_fn(|req: Request| async {
        // 提取路由中的person_id参数
        let route_parts = req.extensions().get::<RouteParts>().ok_or_else(|| {
            ReqwestError::new(ErrorKind::Other, "无法获取路由信息")
        })?;

        let person_id = route_parts.params().get("person_id").ok_or_else(|| {
            ReqwestError::new(ErrorKind::Other, "缺少person_id路径参数")
        })?.to_owned();

        let body = get_person(person_id).await?;
        Ok::<_, ReqwestError>(body.into_response())
    });

    let app = Router::new()
        .route("/", get(get_weather))
        .route_service(
            "/person/:person_id",
            HandleError::new(faillible_person_service, handle_reqwest_error),
        )
        .layer(cors)
        .with_state(client);
        
    let listener = tokio::net::TcpListener::bind("127.0.0.1:1337")
        .await
        .unwrap();
    axum::serve(listener, app).await.unwrap();
}

async fn handle_reqwest_error(err: ReqwestError) -> Response {
    let status = err.status().unwrap_or(reqwest::StatusCode::INTERNAL_SERVER_ERROR);
    let axum_status = StatusCode::from_u16(status.as_u16())
        .unwrap_or(StatusCode::INTERNAL_SERVER_ERROR);
        
    let res_json = Json(serde_json::json!({
        "error": {
            "message": format!("请求出错: {}", err),
        },
    }));
    
    (axum_status, res_json).into_response()
}

// 保留你原有的get_weather函数实现
async fn get_weather() -> Json<Value> {
    Json(serde_json::json!({"message": "weather endpoint"}))
}

关键说明

  • RouteParts的作用:Axum会将路由匹配结果(包括路径参数)存储在Request的extensions中,类型为RouteParts,可以直接取出使用。
  • 错误包装:如果提取参数失败,将错误包装成reqwest::Error,这样就能继续使用?运算符,保持原有错误处理流程的一致性,最终在handle_reqwest_error中统一处理。
  • 参数获取:通过route_parts.params().get("person_id")直接按参数名获取值,无需使用Path提取器,适配service_fn的使用场景。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.03 06:41:02