Signed-off-by: TIANHE <TIANHE@GMAIL.COM>
This commit is contained in:
TIANHE
2026-01-14 23:01:39 +08:00
parent 0172147348
commit 47efb7e024
3 changed files with 38 additions and 14 deletions
+1 -2
View File
@@ -80,8 +80,7 @@ export function runMonitor (id, params = {}) {
return request({ return request({
url: `/api/portfolio/monitors/${id}/run`, url: `/api/portfolio/monitors/${id}/run`,
method: 'post', method: 'post',
data: params, data: params
timeout: 60000 // 60s timeout for monitor API (async mode should return immediately)
}) })
} }
+11 -1
View File
@@ -67,7 +67,17 @@ router.beforeEach((to, from, next) => {
} }
}) })
}) })
.catch(() => { .catch((err) => {
// If token is invalid/expired, clear local auth and redirect to login.
const status = err && err.response && err.response.status
if (status === 401) {
store.dispatch('Logout').finally(() => {
next({ path: loginRoutePath, query: { redirect: to.fullPath } })
NProgress.done()
})
return
}
// Do NOT hard-logout on transient failures (backend down, proxy issue, etc). // Do NOT hard-logout on transient failures (backend down, proxy issue, etc).
// Instead, degrade gracefully with a default role and continue. // Instead, degrade gracefully with a default role and continue.
store.commit('SET_ROLES', [{ id: 'default', permissionList: [] }]) store.commit('SET_ROLES', [{ id: 'default', permissionList: [] }])
+26 -11
View File
@@ -3,13 +3,16 @@ import axios from 'axios'
import storage from 'store' import storage from 'store'
import notification from 'ant-design-vue/es/notification' import notification from 'ant-design-vue/es/notification'
import { VueAxios } from './axios' import { VueAxios } from './axios'
import { ACCESS_TOKEN } from '@/store/mutation-types' import { ACCESS_TOKEN, USER_INFO, USER_ROLES } from '@/store/mutation-types'
// PHPSESSID 存储键名 // PHPSESSID 存储键名
const PHPSESSID_KEY = 'PHPSESSID' const PHPSESSID_KEY = 'PHPSESSID'
// Locale storage key used by vue-i18n (see src/locales/index.js) // Locale storage key used by vue-i18n (see src/locales/index.js)
const LOCALE_KEY = 'lang' const LOCALE_KEY = 'lang'
// Prevent multiple concurrent 401 redirects
let isRedirectingToLogin = false
/** /**
* 获取 token,处理 token 可能是字符串或对象的情况 * 获取 token,处理 token 可能是字符串或对象的情况
*/ */
@@ -53,16 +56,28 @@ const errorHandler = (error) => {
}) })
} }
if (error.response.status === 401 && !(data.result && data.result.isLogin)) { if (error.response.status === 401 && !(data.result && data.result.isLogin)) {
notification.error({ // Token invalid/expired: MUST clear local auth state, otherwise route guard will
message: 'Unauthorized', // detect a stale token and immediately bounce user away from login page.
description: 'Authorization verification failed' if (!isRedirectingToLogin) {
}) isRedirectingToLogin = true
// 不清理本地 token,避免刷新后丢失登录态;仅跳转到登录页 try {
// 项目使用 hash 模式,需要跳转到 /#/user/login storage.remove(ACCESS_TOKEN)
const curHash = window.location.hash || '' storage.remove(USER_INFO)
if (!curHash.includes('/user/login')) { storage.remove(USER_ROLES)
const redirect = encodeURIComponent(curHash.replace('#', '') || '/') storage.remove(PHPSESSID_KEY)
window.location.assign(`/#/user/login?redirect=${redirect}`) } catch (e) {}
notification.error({
message: 'Unauthorized',
description: data.msg || data.message || 'Token invalid or expired, please login again.'
})
// 项目使用 hash 模式,需要跳转到 /#/user/login
const curHash = window.location.hash || ''
if (!curHash.includes('/user/login')) {
const redirect = encodeURIComponent(curHash.replace('#', '') || '/')
window.location.assign(`/#/user/login?redirect=${redirect}`)
}
} }
} }
} }