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

Next.js中RxJS BehaviourSubject状态管理实现失效问题

问题:使用RxJS BehaviourSubject存储JWT后,生成Bearer Token时始终返回null

我尝试在登录时用RxJS BehaviourSubject存储JWT Token,以此给HTTP请求添加Authorization: Bearer ${user.jwtToken}请求头。我认为实现需要满足以下几点:

  • 初始值
  • 可转换为Observable的数据源
  • 可订阅的公共变量

登录时已经通过userSubject.next(user);将用户信息正确传入subject,但每次生成Bearer Token时,accountService.userValue始终为null。

相关代码

账户服务

// 账户服务
// 初始化并设置初始值
const userSubject = new BehaviorSubject(null);
const authApiUrl = "https:testApi";

export const accountService = {
    user: userSubject.asObservable(), get userValue() { return userSubject.value },
    login,
    getAllUsers
};

function login(email, password) {
return fetchWrapper.post(process.env.AuthApiUrl + '/accounts/authenticate', { email, password })
    .then(user => {
        userSubject.next(user);
        localStorage.setItem('user', JSON.stringify(user));
        return user;
    });
}

function getAllUsers() {
return await fetchWrapper.get(process.env.AuthApiUrl + '/accounts/get-all-users'); // 语法错误:未声明async却使用await
}

请求封装器

// 请求封装器
export const fetchWrapper = {
get,
post
};

function post(url, body) {
const requestOptions = {
    method: 'POST',
    headers: { 'Content-Type': 'application/json', ...authHeader(url) },
    credentials: 'include',
    body: JSON.stringify(body)
};
return fetch(url, requestOptions).then(handleResponse);
}

function get(url) {
const requestOptions = {
    method: 'GET',
    headers: authHeader(url)
};
return fetch(url, requestOptions).then(handleResponse);
}

function authHeader(url) {
// 若用户已登录且请求指向API地址,则返回带基础认证凭证的请求头

// accountService.userValue 始终为null???
const user = accountService.userValue;
const isLoggedIn = user && user.jwtToken;
const isApiUrl = url.startsWith(process.env.AuthApiUrl);
if (isLoggedIn && isApiUrl) {
    return { Authorization: `Bearer ${user.jwtToken}` };
} else {
    return {};
}
}

function handleResponse(response) {
return response.text().then(text => {
const data = text && JSON.parse(text);

    if (!response.ok) {
        if ([401, 403].includes(response.status) && accountService.userValue) {
            // 若API返回401未授权或403禁止响应,则自动登出
            accountService.logout();
        }

        const error = (data && data.message) || response.statusText;
        return Promise.reject(error);
    }

    return data;
});
}

问题原因及修复方案

1. 页面刷新后未恢复用户状态

BehaviourSubject的初始值为null,页面刷新后会重置状态,导致userValue回到null。需要在初始化时从localStorage读取已保存的用户信息:

// 账户服务初始化逻辑修改
const storedUser = localStorage.getItem('user');
const userSubject = new BehaviorSubject(storedUser ? JSON.parse(storedUser) : null);

2. 模块循环引用问题

accountService依赖fetchWrapper,而fetchWrapper又依赖accountService,初始化时可能出现accountService未完全导出的情况,导致authHeader获取到的userValue为null。可以通过延迟导入避免循环引用:

function authHeader(url) {
    // 根据实际文件路径调整导入语句
    const { accountService } = require('./accountService');
    const user = accountService.userValue;
    // 后续逻辑保持不变
}

3. 修复getAllUsers语法错误

函数未声明async却使用await会触发语法错误,修改如下:

async function getAllUsers() {
return await fetchWrapper.get(process.env.AuthApiUrl + '/accounts/get-all-users');
}

4. 验证登录返回数据结构

检查登录接口返回的user对象是否包含jwtToken字段,若返回数据结构不符,会导致isLoggedIn判断为false,无法生成Bearer Token。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.03 17:15:37