Commit de73cb84 by Liu

refactor: 优化工具函数、首页和路由处理逻辑

parent 1084a561
......@@ -74,6 +74,19 @@ export function safeLocalStorageSetItem(key: string, value: string): void {
}
}
/**
* 安全地清除 localStorage
* 在无痕模式或存储被禁用时静默失败
*/
export function safeLocalStorageClear(): void {
try {
localStorage.clear()
}
catch {
// 在无痕模式或存储被禁用时,静默失败
}
}
const USER_ROLES_STORAGE_KEY = '__USER_ROLES__'
/**
......@@ -294,9 +307,9 @@ export function getUserRolesForApi(): string[] {
export async function waitForToken(maxWaitTime = 3000): Promise<boolean> {
const startTime = Date.now()
let initialToken = ''
// 先获取初始 token 值
// 先获取初始 token 值(使用安全函数)
try {
const initialTokenStr = window.localStorage.getItem('__TOKEN__') || '""'
const initialTokenStr = safeLocalStorageGetItem('__TOKEN__') || '""'
initialToken = JSON.parse(initialTokenStr) || ''
}
catch {
......@@ -306,7 +319,7 @@ export async function waitForToken(maxWaitTime = 3000): Promise<boolean> {
// 如果初始没有 token,等待 token 出现(从无到有,说明登录完成)
if (!initialToken) {
while (Date.now() - startTime < maxWaitTime) {
const tokenStr = window.localStorage.getItem('__TOKEN__') || '""'
const tokenStr = safeLocalStorageGetItem('__TOKEN__') || '""'
let token = ''
try {
token = JSON.parse(tokenStr) || ''
......@@ -331,7 +344,7 @@ export async function waitForToken(maxWaitTime = 3000): Promise<boolean> {
let tokenChanged = false
const checkTokenChange = () => {
try {
const currentTokenStr = window.localStorage.getItem('__TOKEN__') || '""'
const currentTokenStr = safeLocalStorageGetItem('__TOKEN__') || '""'
const currentToken = JSON.parse(currentTokenStr) || ''
if (currentToken && currentToken !== initialToken) {
tokenChanged = true
......
......@@ -14,7 +14,7 @@ import SdreamLoading from '@/components/SdreamLoading'
import { fetchLoginByToken, fetchLoginByUid } from '@/api/common'
import { fetchSessionConversationId } from '@/api/conversation'
import { fetchCheckTokenApi } from '@/api/chat'
import { getUserRolesFromRoute, safeLocalStorageGetItem, safeSessionStorageGetItem, safeSessionStorageRemoveItem, safeSessionStorageSetItem, waitForToken } from '@/lib/utils'
import { getUserRolesFromRoute, safeLocalStorageGetItem, safeLocalStorageSetItem, safeSessionStorageGetItem, safeSessionStorageRemoveItem, safeSessionStorageSetItem, waitForToken } from '@/lib/utils'
// 从 localStorage 获取 token 的辅助函数
function getTokenFromStorage(): string | null {
......@@ -281,12 +281,32 @@ export const Home: React.FC = () => {
// 使用 replace 避免产生新的历史记录
window.history.replaceState({}, '', currentUrl.toString())
}
// 尝试使用 useLocalStorageState 设置 token,如果失败则使用降级方案
try {
setToken(res.data.token)
}
catch (error) {
// localStorage 被阻止时,使用安全函数降级存储
console.warn('setToken 失败,使用降级方案:', error)
safeLocalStorageSetItem('__TOKEN__', JSON.stringify(res.data.token))
}
if (res.data.userName) {
try {
setUserName(res.data.userName)
}
catch {
// userName 存储失败时使用降级方案
safeLocalStorageSetItem('__USER_NAME__', JSON.stringify(res.data.userName))
}
}
// 确保 token 已写入 localStorage(useLocalStorageState 是同步的,但为了保险起见,使用微任务确保写入完成)
await new Promise(resolve => setTimeout(resolve, 0))
// 验证 token 是否真正写入,如果没有则使用降级方案
const verifyToken = getTokenFromStorage()
if (!verifyToken) {
// 如果 useLocalStorageState 写入失败,使用安全函数再次尝试
safeLocalStorageSetItem('__TOKEN__', JSON.stringify(res.data.token))
}
window.dispatchEvent(
new StorageEvent('storage', {
key: '__TOKEN__',
......@@ -358,12 +378,32 @@ export const Home: React.FC = () => {
currentUrl.searchParams.delete('toolId')
window.history.replaceState({}, '', currentUrl.toString())
}
// 尝试使用 useLocalStorageState 设置 token,如果失败则使用降级方案
try {
setToken(res.data.token)
}
catch (error) {
// localStorage 被阻止时,使用安全函数降级存储
console.warn('setToken 失败,使用降级方案:', error)
safeLocalStorageSetItem('__TOKEN__', JSON.stringify(res.data.token))
}
if (res.data.userName) {
try {
setUserName(res.data.userName)
}
catch {
// userName 存储失败时使用降级方案
safeLocalStorageSetItem('__USER_NAME__', JSON.stringify(res.data.userName))
}
}
// 确保 token 已写入 localStorage(useLocalStorageState 是同步的,但为了保险起见,使用微任务确保写入完成)
await new Promise(resolve => setTimeout(resolve, 0))
// 验证 token 是否真正写入,如果没有则使用降级方案
const verifyToken = getTokenFromStorage()
if (!verifyToken) {
// 如果 useLocalStorageState 写入失败,使用安全函数再次尝试
safeLocalStorageSetItem('__TOKEN__', JSON.stringify(res.data.token))
}
// 主动触发 storage 事件,确保其他组件能监听到变化
window.dispatchEvent(
new StorageEvent('storage', {
......
......@@ -5,7 +5,6 @@ import { clearCurrentTacticsConversation, setCurrentTacticsConversation } from '
import { useAppDispatch, useAppSelector } from '@/store/hook'
import { setIsAsking } from '@/store/chatSlice'
import type { RootState } from '@/store'
import { safeLocalStorageGetItem } from '@/lib/utils'
export function withRouteChangeHandler(WrappedComponent: React.ComponentType) {
let beforeLocationPathName = ''
......@@ -38,7 +37,7 @@ export function withRouteChangeHandler(WrappedComponent: React.ComponentType) {
if (location.pathname === '/') {
// 如果 localStorage 中有 conversationId,不清除,让恢复逻辑处理
// 这样可以保留上一次的历史记录
const savedConversationId = safeLocalStorageGetItem('currentConversationId')
const savedConversationId = window.localStorage.getItem('currentConversationId')
if (!savedConversationId) {
dispatch(clearCurrentConversation())
}
......
......@@ -7,6 +7,7 @@ import type {
} from 'axios'
import type { EnvConfKey } from '@/config/env'
import { envConf } from '@/config/env'
import { safeLocalStorageClear, safeLocalStorageGetItem } from '@/lib/utils'
export interface Response<T> {
data: T
......@@ -31,7 +32,8 @@ service.interceptors.request.use(
(config: any) => {
let token = ''
try {
const tokenStr = window.localStorage.getItem('__TOKEN__')
// 使用安全函数获取 token,避免在第三方页面中访问 localStorage 被阻止
const tokenStr = safeLocalStorageGetItem('__TOKEN__')
if (tokenStr) {
// useLocalStorageState 会将值序列化为 JSON,需要解析
token = JSON.parse(tokenStr) || ''
......@@ -70,8 +72,8 @@ service.interceptors.response.use(
return response.data
}
else if (code === '00000005') {
// 处理登录失效
window.localStorage.clear()
// 处理登录失效(使用安全函数,避免在第三方页面中被阻止)
safeLocalStorageClear()
}
else {
return Promise.reject(new Error(message))
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment