优化登录状态错误时跳转页面到admin/login
This commit is contained in:
@@ -34,6 +34,7 @@ function resolveAdminThinkLang(): string {
|
||||
|
||||
window.requests = []
|
||||
window.tokenRefreshing = false
|
||||
window.authRedirecting = false
|
||||
const pendingMap = new Map()
|
||||
const loadingInstance: LoadingInstance = {
|
||||
target: null,
|
||||
@@ -245,20 +246,119 @@ export default createAxios
|
||||
* 处理异常
|
||||
* @param {*} error
|
||||
*/
|
||||
/** 解析 axios 错误响应体(可能已是对象或 JSON 字符串) */
|
||||
function normalizeAxiosErrorBody(data: unknown): anyObj | null {
|
||||
if (data === undefined || data === null) {
|
||||
return null
|
||||
}
|
||||
if (typeof data === 'string') {
|
||||
try {
|
||||
return JSON.parse(data) as anyObj
|
||||
} catch {
|
||||
return null
|
||||
}
|
||||
}
|
||||
if (typeof data === 'object') {
|
||||
return data as anyObj
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
/**
|
||||
* 后端未登录时通过 HTTP 303 + body.data.type === 'need login' 提示登录(见 Auth::LOGIN_RESPONSE_CODE)。
|
||||
* Axios 将 303 视为失败,不会进入成功拦截器里对 code==303 的分支,需在此与之一致:清 token 并跳登录页。
|
||||
*/
|
||||
function redirectToLoginIfNeedLoginFromHttp303(error: any): boolean {
|
||||
if (!error?.response || error.response.status !== 303) {
|
||||
return false
|
||||
}
|
||||
const body = normalizeAxiosErrorBody(error.response.data)
|
||||
if (!body || typeof body.data !== 'object' || body.data === null) {
|
||||
return false
|
||||
}
|
||||
const needType = (body.data as anyObj).type
|
||||
if (needType !== 'need login') {
|
||||
return false
|
||||
}
|
||||
if (window.authRedirecting) {
|
||||
return true
|
||||
}
|
||||
const isAdminAppFlag = isAdminApp()
|
||||
const loginRouteName = isAdminAppFlag ? 'adminLogin' : 'userLogin'
|
||||
if (router.currentRoute.value.name === loginRouteName) {
|
||||
return true
|
||||
}
|
||||
window.authRedirecting = true
|
||||
const adminInfo = useAdminInfo()
|
||||
const userInfo = useUserInfo()
|
||||
if (isAdminAppFlag) {
|
||||
adminInfo.removeToken()
|
||||
router.replace({ name: loginRouteName }).finally(() => {
|
||||
window.authRedirecting = false
|
||||
})
|
||||
} else {
|
||||
userInfo.removeToken()
|
||||
const to = router.currentRoute.value.fullPath
|
||||
router.replace({ name: loginRouteName, query: to ? { to } : {} }).finally(() => {
|
||||
window.authRedirecting = false
|
||||
})
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
function httpErrorStatusHandle(error: any) {
|
||||
// 处理被取消的请求
|
||||
if (axios.isCancel(error)) return console.error(i18n.global.t('axios.Automatic cancellation due to duplicate request:') + error.message)
|
||||
if (redirectToLoginIfNeedLoginFromHttp303(error)) {
|
||||
return
|
||||
}
|
||||
let message = ''
|
||||
if (error && error.response) {
|
||||
switch (error.response.status) {
|
||||
case 302:
|
||||
message = i18n.global.t('axios.Interface redirected!')
|
||||
break
|
||||
case 303: {
|
||||
const body303 = normalizeAxiosErrorBody(error.response.data)
|
||||
const serverMsg303 = body303 && typeof body303.msg === 'string' ? body303.msg : ''
|
||||
message = serverMsg303 !== '' ? serverMsg303 : i18n.global.t('axios.Interface redirected!')
|
||||
break
|
||||
}
|
||||
case 400:
|
||||
message = i18n.global.t('axios.Incorrect parameter!')
|
||||
break
|
||||
case 401:
|
||||
message = i18n.global.t('axios.You do not have permission to operate!')
|
||||
{
|
||||
const data = error.response.data
|
||||
const serverMsg = data && typeof data.msg === 'string' ? data.msg : ''
|
||||
if (serverMsg) {
|
||||
message = serverMsg
|
||||
}
|
||||
|
||||
const isAdminAppFlag = isAdminApp()
|
||||
const loginRouteName = isAdminAppFlag ? 'adminLogin' : 'userLogin'
|
||||
if (!window.authRedirecting && router.currentRoute.value.name !== loginRouteName) {
|
||||
window.authRedirecting = true
|
||||
|
||||
const adminInfo = useAdminInfo()
|
||||
const userInfo = useUserInfo()
|
||||
if (isAdminAppFlag) {
|
||||
adminInfo.removeToken()
|
||||
router.replace({ name: loginRouteName }).finally(() => {
|
||||
window.authRedirecting = false
|
||||
})
|
||||
} else {
|
||||
userInfo.removeToken()
|
||||
const to = router.currentRoute.value.fullPath
|
||||
router
|
||||
.replace({ name: loginRouteName, query: to ? { to } : {} })
|
||||
.finally(() => {
|
||||
window.authRedirecting = false
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
break
|
||||
case 403:
|
||||
message = i18n.global.t('axios.You do not have permission to operate!')
|
||||
@@ -271,6 +371,49 @@ function httpErrorStatusHandle(error: any) {
|
||||
break
|
||||
case 409:
|
||||
message = i18n.global.t('axios.The same data already exists in the system!')
|
||||
{
|
||||
const data = error.response.data
|
||||
const serverMsg = data && typeof data.msg === 'string' ? data.msg : ''
|
||||
const authExpiredHints = [
|
||||
'Token expiration',
|
||||
'token expiration',
|
||||
'登录态过期',
|
||||
'请重新登录',
|
||||
'Session expired',
|
||||
'session expired',
|
||||
'please login again',
|
||||
'sila log masuk semula',
|
||||
]
|
||||
const looksLikeAuthExpired =
|
||||
serverMsg !== '' && authExpiredHints.some((hint) => serverMsg.toLowerCase().includes(hint.toLowerCase()))
|
||||
|
||||
if (looksLikeAuthExpired) {
|
||||
message = serverMsg
|
||||
|
||||
const isAdminAppFlag = isAdminApp()
|
||||
const loginRouteName = isAdminAppFlag ? 'adminLogin' : 'userLogin'
|
||||
if (!window.authRedirecting && router.currentRoute.value.name !== loginRouteName) {
|
||||
window.authRedirecting = true
|
||||
|
||||
const adminInfo = useAdminInfo()
|
||||
const userInfo = useUserInfo()
|
||||
if (isAdminAppFlag) {
|
||||
adminInfo.removeToken()
|
||||
router.replace({ name: loginRouteName }).finally(() => {
|
||||
window.authRedirecting = false
|
||||
})
|
||||
} else {
|
||||
userInfo.removeToken()
|
||||
const to = router.currentRoute.value.fullPath
|
||||
router
|
||||
.replace({ name: loginRouteName, query: to ? { to } : {} })
|
||||
.finally(() => {
|
||||
window.authRedirecting = false
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break
|
||||
case 500:
|
||||
message = i18n.global.t('axios.Server internal error!')
|
||||
|
||||
1
web/types/global.d.ts
vendored
1
web/types/global.d.ts
vendored
@@ -3,6 +3,7 @@ interface Window {
|
||||
lazy: number
|
||||
unique: number
|
||||
tokenRefreshing: boolean
|
||||
authRedirecting: boolean
|
||||
requests: Function[]
|
||||
eventSource: EventSource
|
||||
loadLangHandle: Record<string, any>
|
||||
|
||||
Reference in New Issue
Block a user