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

在Axum中使用Mutex时如何修复‘future returned by is not Send’错误?

问题原因

你遇到的错误本质是:标准库std::sync::Mutex的MutexGuard不实现Send trait,而await会让当前任务可能被调度到其他线程执行,编译器不允许持有非Send类型的同时执行异步操作。你的代码里持有锁的verifiers变量一直存活到request_async().await之后,导致锁跨异步调用持有,触发编译错误。

解决方法

方案1:缩短标准库Mutex的持有时间

核心思路是仅在获取PKCE verifier的瞬间持有锁,拿到verifier后立即释放锁,再执行异步请求。

修改后的代码:

#[debug_handler]
async fn callback(
    State(state): State<AppState>,
    Query(auth_request): Query<AuthRequest>,
) -> Result<impl IntoResponse, impl IntoResponse> {
    let auth_request = auth_request;

    // 用代码块限制锁的作用域,块结束后自动释放锁
    let pkce_verifier_str = {
        let verifiers = state.verifiers.lock().unwrap();
        // 克隆字符串拿到所有权,避免锁释放后引用失效
        verifiers.get(&auth_request.state).unwrap().clone()
    };
    let pkce_verifier = PkceCodeVerifier::new(pkce_verifier_str);

    let _token_result = match state
        .oauth_client
        .exchange_code(AuthorizationCode::new(auth_request.code))
        .set_pkce_verifier(pkce_verifier)
        .request_async(async_http_client)
        .await
    {
        Ok(res) => res,
        Err(e) => {
            error!("could not exchange code: {e}");
            return Err((StatusCode::INTERNAL_SERVER_ERROR, e.to_string()));
        }
    };

    // 用完verifier后从HashMap删除,避免内存泄漏
    state.verifiers.lock().unwrap().remove(&auth_request.state);

    Ok(Redirect::temporary("/"))
}

方案2:改用Tokio异步Mutex(推荐)

Axum基于Tokio运行时,使用tokio::sync::Mutex更适配异步场景,它返回的MutexGuard实现了Send,允许跨await持有(仍建议及时释放以保证性能)。

第一步:修改AppState类型

use tokio::sync::Mutex;

#[derive(Clone)]
struct AppState {
    db: PgPool,
    oauth_client: BasicClient,
    verifiers: Arc<Mutex<HashMap<String, String>>>,
}

第二步:修改回调函数

#[debug_handler]
async fn callback(
    State(state): State<AppState>,
    Query(auth_request): Query<AuthRequest>,
) -> Result<impl IntoResponse, impl IntoResponse> {
    let auth_request = auth_request;

    // 异步获取锁,不会阻塞线程
    let verifiers = state.verifiers.lock().await;
    let pkce_verifier_str = verifiers.get(&auth_request.state).unwrap().clone();
    drop(verifiers); // 手动释放锁,也可等变量自动离开作用域

    let pkce_verifier = PkceCodeVerifier::new(pkce_verifier_str);

    let _token_result = match state
        .oauth_client
        .exchange_code(AuthorizationCode::new(auth_request.code))
        .set_pkce_verifier(pkce_verifier)
        .request_async(async_http_client)
        .await
    {
        Ok(res) => res,
        Err(e) => {
            error!("could not exchange code: {e}");
            return Err((StatusCode::INTERNAL_SERVER_ERROR, e.to_string()));
        }
    };

    // 删除已使用的verifier
    state.verifiers.lock().await.remove(&auth_request.state);

    Ok(Redirect::temporary("/"))
}
关键注意点
  • PKCE verifier是一次性使用的,用完必须从HashMap中删除,避免内存无限增长。
  • 标准库Mutex适合同步场景,异步框架中优先选择Tokio的异步Mutex,使用更灵活且符合运行时设计。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.30 02:12:43