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

Rust Axum跨请求传递状态编译异常问题排查

编译失败原因及修复方案

核心问题

你的代码编译失败的根本原因是:持有标准库std::sync::Mutex的锁(MutexGuard)时执行异步await操作,导致返回的Future不满足Send约束。

标准库的MutexGuard没有实现Send trait,它被设计用于同步代码场景,不能跨线程传递。而Axum的Handler要求处理函数返回的Future必须是Send的(因为Axum默认在多线程运行时调度任务)。当你在持有MutexGuard的代码块里调用.await(比如数据库更新的UserBmc::update().await),异步任务的状态会包含这个非Send的MutexGuard,导致整个Future不满足Send,触发编译错误。

而单独执行读取验证码或数据库更新时不会报错:

  • 单独读取验证码:锁在同步代码块内就释放了,Future中不包含MutexGuard,满足Send;
  • 单独更新数据库:没有持有MutexGuard,Future自然满足Send。

修复方案

有两种可行的修复方式,根据你的需求选择:

方案1:先释放锁,再执行异步操作

调整代码逻辑,先从锁中取出验证码,立刻释放锁,再执行数据库更新的异步操作:

pub async fn verify_check(
    ctx: CtxW,
    manager: &Manager,
    params: ParamsUpdateData<u32>,
) -> Result<User> {
    let ParamsUpdateData { data } = params;
    let code = data;

    let verify_store = Arc::clone(&manager.verify_store);
    let username = ctx.username.clone();
    let user_id = ctx.user_id.clone();

    // 同步块内获取验证码,离开块后自动释放锁
    let stored_code = {
        let guard = verify_store.try_lock().map_err(|_| WebError::VerificationProblem)?;
        guard.get(&username).copied().ok_or(WebError::VerificationProblem)?
    };

    if stored_code == code {
        println!("Its a match");
        let data = UserUpdate {
            auth_level: None,
            verified: Some(true),
        };
        let user = UserBmc::update::<UserUpdate, User>(&ctx.into(), &manager.mm, user_id, &data).await?;
        Ok(user)
    } else {
        Err(WebError::VerificationProblem)
    }
}

方案2:使用异步锁替换标准库锁

将std::sync::Mutex替换为Tokio提供的tokio::sync::Mutex,它的MutexGuard实现了Send trait,可以安全地跨越await点:

  1. 首先修改Manager的定义:
use tokio::sync::Mutex;
use std::collections::HashMap;
use std::sync::Arc;

struct Manager {
    // 保留其他字段...
    verify_store: Arc<Mutex<HashMap<String, u32>>>,
}
  1. 更新验证码存储函数verify_request:
pub async fn verify_request(ctx: CtxW, manager: &Manager) -> Result<String> {
    let verify_store = manager.verify_store.clone();
    let username = ctx.username.clone();
    let rng = rand::rng().random_range(0..=10000);

    // 使用异步lock,需要await
    let mut guard = verify_store.lock().await.map_err(|_| WebError::VerificationProblem)?;
    guard.insert(username, rng);

    Ok("Verify request sent to mc server".to_string())
}
  1. 更新验证码校验函数verify_check:
pub async fn verify_check(
    ctx: CtxW,
    manager: &Manager,
    params: ParamsUpdateData<u32>,
) -> Result<User> {
    let ParamsUpdateData { data } = params;
    let code = data;

    let verify_store = Arc::clone(&manager.verify_store);
    let username = ctx.username.clone();
    let user_id = ctx.user_id.clone();

    // 使用异步try_lock,需要await
    let guard = verify_store.try_lock().await.map_err(|_| WebError::VerificationProblem)?;
    let stored_code = guard.get(&username).copied().ok_or(WebError::VerificationProblem)?;

    if stored_code == code {
        println!("Its a match");
        let data = UserUpdate {
            auth_level: None,
            verified: Some(true),
        };
        let user = UserBmc::update::<UserUpdate, User>(&ctx.into(), &manager.mm, user_id, &data).await?;
        Ok(user)
    } else {
        Err(WebError::VerificationProblem)
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.01 22:23:11