在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
相关产品推荐
相关产品推荐

