diff --git a/screen-vue/src/utils/request.js b/screen-vue/src/utils/request.js index a10d462..595e4ad 100644 --- a/screen-vue/src/utils/request.js +++ b/screen-vue/src/utils/request.js @@ -2,6 +2,7 @@ import axios from 'axios' import { ElMessage } from 'element-plus' import router from '@/router' +// 创建axios实例 const service = axios.create({ baseURL: import.meta.env.PROD ? '' : '/api', timeout: 10000, @@ -10,23 +11,59 @@ const service = axios.create({ } }) +// 无需token的白名单接口 +const WHITE_LIST_PATHS = ['/userLogin', '/register']; + +/** + * 检查路径是否在白名单中 + * @param {string} url 请求路径 + * @returns {boolean} 是否在白名单 + */ +const isInWhiteList = (url) => { + if (!url) return false; + return WHITE_LIST_PATHS.some(path => url.includes(path)); +}; + +/** + * 处理登录失效/无token逻辑 + */ +const handleLoginExpired = () => { + // 清除无效token + localStorage.removeItem('token'); + + if (router.currentRoute.path !== '/login') { + const redirect = encodeURIComponent(router.currentRoute.fullPath); + router.push({ + path: '/login', + query: { redirect } + }).catch(err => { + console.warn('路由跳转登录页失败', err); + }); + ElMessage.error('登录状态已失效,请重新登录'); + } +}; + +// 请求拦截器 service.interceptors.request.use( (config) => { - const excludePaths = ['/userLogin', '/register']; - if (!excludePaths.some(path => config.url?.includes(path))) { - const token = localStorage.getItem('token'); - if (token) { - config.headers.Authorization = `Bearer ${token}`; - } + if (isInWhiteList(config.url)) { + return config; } - return config + const token = localStorage.getItem('token'); + if (!token) { + handleLoginExpired(); + return Promise.reject(new Error('未检测到登录凭证,请先登录')); + } + config.headers.Authorization = `Bearer ${token}`; + return config; }, (error) => { console.error('【请求拦截器错误】', error); - return Promise.reject(error) + return Promise.reject(error); } -) +); +// 响应拦截器 service.interceptors.response.use( (response) => { const res = response.data; @@ -40,56 +77,25 @@ service.interceptors.response.use( return res.data; }, (error) => { - console.error('【响应拦截器错误】', error); - if (isLoginExpiredError(error)) { - handleLoginExpired(); - return Promise.reject(new Error('登录状态已失效,请重新登录')); - } - if (!error.response) { - if (error.message.includes('Network Error') || error.message.includes('timeout')) { - router.push("/login").catch(err => { - console.warn('路由跳转失败', err); - }); + const errMsg = error.message.toLowerCase(); + if (errMsg.includes('network error') || errMsg.includes('timeout')) { + ElMessage.error('网络异常,请检查网络连接'); } else { ElMessage.error('请求失败,请稍后重试'); } return Promise.reject(error); } - + + if (error.response.status === 401) { + handleLoginExpired(); + return Promise.reject(new Error('登录状态已失效,请重新登录')); + } + + // 其他错误提示 ElMessage.error(error.response.data?.msg || error.message || '接口请求失败'); return Promise.reject(error); } -) +); -function isLoginExpiredError(error) { - if (error.response && error.response.status === 401) { - return true; - } - - const errorMsg = error.message.toLowerCase(); - const expiredKeywords = [ - 'token expired', 'invalid token', '未授权', - '登录失效', '认证失败', '401' - ]; - const networkKeywords = ['network error', 'timeout', '网络']; - - return ( - expiredKeywords.some(keyword => errorMsg.includes(keyword.toLowerCase())) && - !networkKeywords.some(keyword => errorMsg.includes(keyword.toLowerCase())) - ); -} - -function handleLoginExpired() { - localStorage.removeItem('token'); - - if (router.currentRoute.path !== '/login') { - const redirect = encodeURIComponent(router.currentRoute.fullPath); - router.push("/login").catch(err => { - console.warn('路由跳转失败', err); - }); - ElMessage.error('登录状态已失效,请重新登录'); - } -} - -export default service \ No newline at end of file +export default service; \ No newline at end of file