React应用重定向至子域后如何持久化本地存储并避免重复登录
解决方案
1. 共享登录状态:调整Cookie域属性
主域和子域默认无法共享Cookie,这是导致重新登录的核心原因。需要在后端设置登录Cookie时,指定domain为.localhost(注意前缀的点),让所有子域都能读取该Cookie。
以Express后端为例,设置Cookie的代码示例:
res.cookie('authToken', userToken, { domain: '.localhost', // 允许所有localhost子域访问 httpOnly: true, // 防止XSS攻击 secure: process.env.NODE_ENV === 'production', // 生产环境启用HTTPS sameSite: 'lax', // 平衡安全与可用性 maxAge: 7 * 24 * 60 * 60 * 1000 // 有效期7天 });
开发环境下,部分浏览器(如Chrome)对localhost的Cookie共享有特殊处理,若遇到问题可尝试用自定义域名(如app.local和user.app.local)配合hosts文件映射。
2. 跨子域共享本地存储数据
LocalStorage/SessionStorage受同源策略限制,主域和子域无法直接互相访问,可通过以下两种方式解决:
- 用Cookie替代本地存储:将用户关键信息(如ID、用户名)存入共享Cookie,子域直接从Cookie读取数据,这种方式最简单可靠。
- 通过postMessage传递数据:若必须使用本地存储,可在子域页面加载时向主域发送请求,主域返回用户数据。示例代码:
子域页面:
主域页面需保留监听逻辑(可在主域的全局入口文件中添加):window.addEventListener('load', () => { // 向主域发送数据请求 window.postMessage({ type: 'GET_USER_DATA' }, 'http://localhost:3000'); }); // 接收主域返回的数据 window.addEventListener('message', (event) => { if (event.origin === 'http://localhost:3000' && event.data.type === 'USER_DATA') { // 将数据存入子域本地存储 localStorage.setItem('user', JSON.stringify(event.data.payload)); // 更新子域Redux状态 store.dispatch({ type: 'SET_USER', payload: event.data.payload }); } });window.addEventListener('message', (event) => { if (event.origin.includes('.localhost:3000') && event.data.type === 'GET_USER_DATA') { const userData = localStorage.getItem('user'); event.source.postMessage({ type: 'USER_DATA', payload: userData ? JSON.parse(userData) : null }, event.origin); } });
3. 同步Redux状态
Redux状态仅存在于当前页面内存,重定向到子域后会丢失,需重新初始化:
- 从共享Cookie/本地存储加载状态:在子域的Redux初始化时,读取共享Cookie或通过postMessage获取的用户数据,dispatch action初始化状态。示例:
// 子域App组件 useEffect(() => { const authToken = Cookies.get('authToken'); if (authToken) { // 调用验证接口获取用户信息 fetch('/api/verify-token', { headers: { Authorization: `Bearer ${authToken}` } }) .then(res => res.json()) .then(user => { store.dispatch({ type: 'SET_USER', payload: user }); }); } }, []); - 用Cookie持久化Redux状态:使用
redux-persist配合Cookie存储替代LocalStorage,实现跨子域状态同步。示例配置:import { persistStore, persistReducer } from 'redux-persist'; import CookieStorage from 'redux-persist-cookie-storage'; import Cookies from 'js-cookie'; const persistConfig = { key: 'root', storage: new CookieStorage(Cookies, { domain: '.localhost', secure: process.env.NODE_ENV === 'production', }), whitelist: ['user'] // 仅持久化user模块状态 }; const persistedReducer = persistReducer(persistConfig, rootReducer); const store = createStore(persistedReducer); const persistor = persistStore(store);
4. 优化重定向逻辑
确保Cookie设置完成后再执行重定向,避免因Cookie未生效导致子域无法读取状态:
// 登录接口调用完成后,等待Cookie写入再跳转 async function handleLogin() { const response = await fetch('/api/login', { method: 'POST', body: JSON.stringify(loginForm) }); const data = await response.json(); // 延迟100ms确保Cookie写入(或根据后端响应确认) setTimeout(() => { window.location.href = `http://${data.result.username}.localhost:3000/`; }, 100); }
内容的提问来源于stack exchange,提问作者r121
相关产品推荐
相关产品推荐

