Commit f5f96faf by Liu

fix:处理token返回后再调用业务接口

parent e0072bcc
...@@ -285,3 +285,85 @@ export function getUserRolesForApi(): string[] { ...@@ -285,3 +285,85 @@ export function getUserRolesForApi(): string[] {
// 直接从路由中获取 userRoles(路由参数是唯一真实来源) // 直接从路由中获取 userRoles(路由参数是唯一真实来源)
return getUserRolesFromRoute() return getUserRolesFromRoute()
} }
/**
* 等待 token 就绪,确保登录接口返回后才继续
* @param maxWaitTime 最大等待时间(毫秒),默认 3000ms
* @returns Promise<boolean> 返回 true 表示 token 已就绪,false 表示超时
*/
export async function waitForToken(maxWaitTime = 3000): Promise<boolean> {
const startTime = Date.now()
let initialToken = ''
// 先获取初始 token 值
try {
const initialTokenStr = window.localStorage.getItem('__TOKEN__') || '""'
initialToken = JSON.parse(initialTokenStr) || ''
}
catch {
initialToken = ''
}
// 如果初始没有 token,等待 token 出现(从无到有,说明登录完成)
if (!initialToken) {
while (Date.now() - startTime < maxWaitTime) {
const tokenStr = window.localStorage.getItem('__TOKEN__') || '""'
let token = ''
try {
token = JSON.parse(tokenStr) || ''
}
catch {
token = ''
}
if (token) {
// token 从无到有,说明登录完成,再等待一小段时间确保写入完成
await new Promise(resolve => setTimeout(resolve, 200))
return true
}
// 等待 100ms 后再次检查
await new Promise(resolve => setTimeout(resolve, 100))
}
return false
}
// 如果初始有 token,可能是旧 token 或新 token
// 等待一小段时间,确保登录流程有足够时间完成(登录接口可能会更新 token)
// 同时监听 token 变化
let tokenChanged = false
const checkTokenChange = () => {
try {
const currentTokenStr = window.localStorage.getItem('__TOKEN__') || '""'
const currentToken = JSON.parse(currentTokenStr) || ''
if (currentToken && currentToken !== initialToken) {
tokenChanged = true
}
}
catch {
// 忽略解析错误
}
}
// 监听 storage 事件(跨标签页)
window.addEventListener('storage', checkTokenChange)
// 轮询检查(同标签页)
const interval = setInterval(checkTokenChange, 100)
// 等待最多 1 秒,检测 token 是否变化
const waitForChange = new Promise<void>((resolve) => {
setTimeout(() => {
window.removeEventListener('storage', checkTokenChange)
clearInterval(interval)
resolve()
}, 1000)
})
await waitForChange
// 如果 token 变化了,说明登录完成,再等待一小段时间确保写入完成
if (tokenChanged) {
await new Promise(resolve => setTimeout(resolve, 200))
return true
}
// 如果 token 没有变化,可能是已经登录完成,但为了确保登录流程完成,再等待一小段时间
await new Promise(resolve => setTimeout(resolve, 300))
return true
}
...@@ -8,7 +8,7 @@ import { TacticsWelcome } from './components/TacticsWelcome' ...@@ -8,7 +8,7 @@ import { TacticsWelcome } from './components/TacticsWelcome'
import { clearTacticsNavigationFlag, createTacticsConversation, fetchTacticsConversations } from '@/store/tacticsSlice' import { clearTacticsNavigationFlag, createTacticsConversation, fetchTacticsConversations } from '@/store/tacticsSlice'
import { useAppDispatch, useAppSelector } from '@/store/hook' import { useAppDispatch, useAppSelector } from '@/store/hook'
import type { RootState } from '@/store' import type { RootState } from '@/store'
import { getUserRolesFromRoute, safeLocalStorageGetItem } from '@/lib/utils' import { getUserRolesFromRoute, safeLocalStorageGetItem, waitForToken } from '@/lib/utils'
import { TacticsChatEditor } from '@/components/TacticsChatEditor' import { TacticsChatEditor } from '@/components/TacticsChatEditor'
export const TacticsHome: React.FC = () => { export const TacticsHome: React.FC = () => {
...@@ -111,10 +111,12 @@ export const TacticsHome: React.FC = () => { ...@@ -111,10 +111,12 @@ export const TacticsHome: React.FC = () => {
return {} as Partial<any> return {} as Partial<any>
}, [orderMeta, tacticsMeta, userMeta]) }, [orderMeta, tacticsMeta, userMeta])
const initTacticsConversation = () => { const initTacticsConversation = async () => {
const fromCollect = location.state?.fromCollect const fromCollect = location.state?.fromCollect
// 只有在访问问答首页时才创建新对话 // 只有在访问问答首页时才创建新对话
if (!fromCollect && location.pathname === '/tactics') { if (!fromCollect && location.pathname === '/tactics') {
// 等待 token 就绪后再调用接口
await waitForToken()
dispatch( dispatch(
createTacticsConversation({ createTacticsConversation({
conversationData: getConversationExtra(), conversationData: getConversationExtra(),
...@@ -216,6 +218,7 @@ export const TacticsHome: React.FC = () => { ...@@ -216,6 +218,7 @@ export const TacticsHome: React.FC = () => {
// 确保 token 存在后再执行业务逻辑 // 确保 token 存在后再执行业务逻辑
if (actualToken) { if (actualToken) {
hasInitialized.current = true hasInitialized.current = true
// initTacticsConversation 内部已有 waitForToken 等待,这里直接调用
initTacticsConversation() initTacticsConversation()
dispatch(fetchTacticsConversations()) dispatch(fetchTacticsConversations())
} }
...@@ -242,6 +245,7 @@ export const TacticsHome: React.FC = () => { ...@@ -242,6 +245,7 @@ export const TacticsHome: React.FC = () => {
if (actualToken) { if (actualToken) {
hasInitialized.current = true hasInitialized.current = true
// initTacticsConversation 内部已有 waitForToken 等待,这里直接调用
initTacticsConversation() initTacticsConversation()
dispatch(fetchTacticsConversations()) dispatch(fetchTacticsConversations())
} }
......
...@@ -14,7 +14,7 @@ import SdreamLoading from '@/components/SdreamLoading' ...@@ -14,7 +14,7 @@ import SdreamLoading from '@/components/SdreamLoading'
import { fetchLoginByToken, fetchLoginByUid } from '@/api/common' import { fetchLoginByToken, fetchLoginByUid } from '@/api/common'
import { fetchSessionConversationId } from '@/api/conversation' import { fetchSessionConversationId } from '@/api/conversation'
import { fetchCheckTokenApi } from '@/api/chat' import { fetchCheckTokenApi } from '@/api/chat'
import { getUserRolesFromRoute, safeLocalStorageGetItem, safeSessionStorageGetItem, safeSessionStorageRemoveItem, safeSessionStorageSetItem } from '@/lib/utils' import { getUserRolesFromRoute, safeLocalStorageGetItem, safeSessionStorageGetItem, safeSessionStorageRemoveItem, safeSessionStorageSetItem, waitForToken } from '@/lib/utils'
// 从 localStorage 获取 token 的辅助函数 // 从 localStorage 获取 token 的辅助函数
function getTokenFromStorage(): string | null { function getTokenFromStorage(): string | null {
...@@ -88,6 +88,8 @@ export const Home: React.FC = () => { ...@@ -88,6 +88,8 @@ export const Home: React.FC = () => {
// 获取会话ID并加载历史记录 // 获取会话ID并加载历史记录
const getSessionConversationId = async (data?: any) => { const getSessionConversationId = async (data?: any) => {
try { try {
// 等待 token 就绪后再调用接口
await waitForToken()
// 从 sessionStorage 获取 toolId 作为 busiId // 从 sessionStorage 获取 toolId 作为 busiId
const toolId = safeSessionStorageGetItem('currentToolId') || '' const toolId = safeSessionStorageGetItem('currentToolId') || ''
const requestData = { const requestData = {
......
...@@ -29,9 +29,20 @@ const service = axios.create({ ...@@ -29,9 +29,20 @@ const service = axios.create({
service.interceptors.request.use( service.interceptors.request.use(
(config: any) => { (config: any) => {
const token = window.localStorage.getItem('__TOKEN__') || '""' let token = ''
try {
const tokenStr = window.localStorage.getItem('__TOKEN__')
if (tokenStr) {
// useLocalStorageState 会将值序列化为 JSON,需要解析
token = JSON.parse(tokenStr) || ''
}
}
catch {
// 如果解析失败,使用空字符串
token = ''
}
config.headers = { config.headers = {
'X-Token': JSON.parse(token), 'X-Token': token,
'X-Request-Id': `${Date.now()}${Math.random().toString(36).substring(2)}`, 'X-Request-Id': `${Date.now()}${Math.random().toString(36).substring(2)}`,
'X-Request-By': config.url, 'X-Request-By': config.url,
} }
......
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