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

Leptos-Axum SSR条件路由渲染问题:初始加载跳转异常

问题根源与修复方案

核心问题

你的代码存在两个关键问题,导致初始加载受保护路由时触发错误重定向:

  1. 初始渲染时状态未及时更新
    你用create_effect来设置current_user,但create_effect是组件渲染完成后才执行的副作用。路由守卫的<Show>条件会在初始渲染(包括客户端hydrate和SSR)时先判断,此时global_state.current_user还是初始的None,直接触发重定向。等create_effect执行完设置正确状态时,重定向已经生效了。

  2. SSR无法访问浏览器localStorage
    服务器渲染阶段根本读不到浏览器的localStorage,所以SSR时current_user默认是None,会直接输出<Redirect>标签。客户端拿到这个SSR生成的HTML后,会立即执行重定向,即使之后hydrate时获取到了用户信息也无法挽回。


具体修复步骤

1. 同步初始化客户端状态(替换原create_effect逻辑)

把原来的create_effect改成同步执行的初始化逻辑,确保组件渲染前就设置好current_user:

let global_state = use_context::<GlobalState>().unwrap();

// 客户端环境下,同步读取localStorage设置用户状态
#[cfg(client)]
{
    let current_user = AuthService::get_current_user();
    if current_user.user_name.is_empty() {
        global_state.current_user.set(None);
    } else {
        global_state.current_user.set(Some(CurrentUser {
            user_name: create_rw_signal(current_user.user_name.clone()),
        }));
    }
}

2. 适配SSR场景(通过Cookie验证用户)

如果要让SSR正确渲染受保护页面,需要把JWT存在HttpOnly Cookie里(比localStorage更安全),服务器端在渲染前验证Cookie中的JWT:

// 服务器环境下,从Cookie读取JWT并验证用户
#[cfg(server)]
{
    let req = use_request();
    let jwt_cookie = req.cookies().get("jwt").map(|c| c.value().to_string());
    
    if let Some(jwt) = jwt_cookie {
        match AuthService::verify_jwt(&jwt) {
            Ok(user) => {
                global_state.current_user.set(Some(CurrentUser {
                    user_name: create_rw_signal(user.user_name),
                }));
            }
            Err(_) => global_state.current_user.set(None),
        }
    } else {
        global_state.current_user.set(None);
    }
}

3. 路由守卫适配异步场景(可选)

如果AuthService::get_current_user是异步操作(比如需要调用API验证JWT),要用create_resource结合Suspense等待状态加载完成,避免初始判断错误:

// 异步获取用户资源
let current_user_resource = create_resource(
    || (),
    |_| async { AuthService::get_current_user().await }
);

// 根据资源更新全局状态
create_effect(move |_| {
    if let Some(current_user) = current_user_resource.read() {
        if current_user.user_name.is_empty() {
            global_state.current_user.set(None);
        } else {
            global_state.current_user.set(Some(CurrentUser {
                user_name: create_rw_signal(current_user.user_name.clone()),
            }));
        }
    }
});

// 修改路由守卫,等待资源加载完成再判断
<Route path="/" view=move || {
    view! {
        <Show when=move || {
            current_user_resource.read().is_some() && global_state.current_user.get().is_none()
        }>
            <Redirect path=LOGIN_URL/>
        </Show>
        <Suspense fallback=|| view! { <div>加载中...</div> }>
            <Outlet/>
        </Suspense>
    }
}>
  <Route path="/" view=HomePage/>
</Route>

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.23 21:06:04