8.0 KiB
8.0 KiB
未登录接口调用问题修复
🔍 问题描述
错误现象
在用户未登录时,sys_parameter/key 接口被调用,因为没有 token 导致接口报错。
错误原因
在 demo-project/src/main.js 的 mounted 钩子中,无条件调用了 getSysTitle action:
mounted() {
AdminFramework.uiTool.setRem()
// ❌ 无论是否登录都调用
this.$store.dispatch('app/getSysTitle', {
defaultTitle: 'Demo 管理系统',
defaultLogo: ''
})
}
getSysTitle action 会调用后端接口:
paramSetupServer.getOne('sys_title')- 获取系统标题paramSetupServer.getOne('sys_logo')- 获取系统 Logo
这些接口需要 token 认证,但在应用启动时用户可能还没登录,导致接口调用失败。
调用时机问题
应用启动
↓
Vue 实例 mounted
↓
调用 getSysTitle ← ❌ 此时可能未登录
↓
调用后端接口
↓
没有 token,接口报错 ❌
✅ 解决方案
方案:只在已登录时调用接口
核心思路:
- 在调用
getSysTitle前检查是否已登录(是否有 token) - 已登录:调用接口获取系统标题
- 未登录:直接使用默认标题
修改 1:demo-project/src/main.js
修改前:
mounted() {
AdminFramework.uiTool.setRem()
// ❌ 无条件调用,可能导致未登录时接口报错
this.$store.dispatch('app/getSysTitle', {
defaultTitle: 'Demo 管理系统',
defaultLogo: ''
})
}
修改后:
mounted() {
AdminFramework.uiTool.setRem()
// ✅ 检查是否已登录
const token = this.$store.state.user.token
if (token) {
// 已登录,调用接口获取系统标题
this.$store.dispatch('app/getSysTitle', {
defaultTitle: 'Demo 管理系统',
defaultLogo: ''
})
} else {
// 未登录,直接设置默认标题
document.title = 'Demo 管理系统'
}
}
修改 2:src/store/app.js 的 getSysTitle action
修改前:
async getSysTitle({ state, commit }, { defaultTitle = '智能代码平台', defaultLogo = '' }) {
let formModel = {
title: defaultTitle,
logoUrl: defaultLogo
}
try {
// ❌ 直接调用接口,不检查是否已登录
let res1 = await paramSetupServer.getOne('sys_title')
if (res1 && res1.data) {
formModel.title = res1.data.value
document.title = res1.data.value
}
let res2 = await paramSetupServer.getOne('sys_logo')
if (res2 && res2.data) {
formModel.logoUrl = res2.data.value
}
} catch (error) {
console.warn('获取系统标题失败,使用默认标题:', error || '接口调用失败')
document.title = formModel.title
}
commit('setSysTitle', formModel)
}
修改后:
async getSysTitle({ state, commit, rootState }, { defaultTitle = '智能代码平台', defaultLogo = '' }) {
let formModel = {
title: defaultTitle,
logoUrl: defaultLogo
}
// ✅ 检查是否已登录(有 token)
const token = rootState.user.token
if (token) {
// 已登录,尝试从后端获取系统标题
try {
let res1 = await paramSetupServer.getOne('sys_title')
if (res1 && res1.data) {
formModel.title = res1.data.value
document.title = res1.data.value
}
let res2 = await paramSetupServer.getOne('sys_logo')
if (res2 && res2.data) {
formModel.logoUrl = res2.data.value
}
} catch (error) {
console.warn('获取系统标题失败,使用默认标题:', error || '接口调用失败')
document.title = formModel.title
}
} else {
// 未登录,直接使用默认标题
document.title = formModel.title
}
commit('setSysTitle', formModel)
}
📊 修复后的流程
未登录时
应用启动
↓
Vue 实例 mounted
↓
检查 token
↓
token 不存在 ✅
↓
直接设置默认标题 "Demo 管理系统"
↓
不调用后端接口 ✅
已登录时
应用启动
↓
Vue 实例 mounted
↓
检查 token
↓
token 存在 ✅
↓
调用 getSysTitle action
↓
检查 rootState.user.token
↓
token 存在 ✅
↓
调用后端接口获取系统标题
↓
成功:使用后端返回的标题
失败:使用默认标题
登录流程
用户登录
↓
保存 token 到 store
↓
刷新页面
↓
应用重新启动
↓
Vue 实例 mounted
↓
检查 token(此时有 token)✅
↓
调用 getSysTitle 获取系统标题
🎯 优化点
1. 双重检查
第一层检查(main.js):
const token = this.$store.state.user.token
if (token) {
this.$store.dispatch('app/getSysTitle', ...)
}
第二层检查(app.js):
const token = rootState.user.token
if (token) {
// 调用接口
}
为什么需要双重检查?
- 第一层:避免不必要的 action 调用
- 第二层:防止 action 被其他地方调用时没有检查 token
2. 默认标题处理
未登录时:
document.title = 'Demo 管理系统'
已登录但接口失败时:
document.title = formModel.title // 使用传入的 defaultTitle
已登录且接口成功时:
document.title = res1.data.value // 使用后端返回的标题
3. 错误处理
try {
// 调用接口
} catch (error) {
console.warn('获取系统标题失败,使用默认标题:', error || '接口调用失败')
document.title = formModel.title
}
即使接口调用失败,也会优雅降级到默认标题,不影响用户使用。
✅ 验证清单
未登录场景
- ✅ 访问首页显示登录页面
- ✅ 页面标题显示 "Demo 管理系统"
- ✅ 控制台没有接口报错
- ✅ Network 标签中没有
sys_parameter/key请求
已登录场景
- ✅ 登录成功后刷新页面
- ✅ 页面标题显示系统标题(如果后端有配置)
- ✅ 如果后端接口失败,显示默认标题
- ✅ 系统 Logo 正确显示(如果后端有配置)
登录流程
- ✅ 输入用户名密码
- ✅ 点击登录
- ✅ 登录成功
- ✅ 页面刷新
- ✅ 进入系统首页
- ✅ 系统标题正确显示
💡 最佳实践
1. 接口调用前检查认证状态
// ✅ 好的做法
if (token) {
await api.getData()
}
// ❌ 不好的做法
try {
await api.getData() // 可能因为没有 token 而失败
} catch (error) {
// 处理错误
}
2. 提供默认值
// ✅ 好的做法
const title = res.data?.value || defaultTitle
// ❌ 不好的做法
const title = res.data.value // 可能是 undefined
3. 优雅降级
// ✅ 好的做法
if (token) {
try {
const data = await api.getData()
useData(data)
} catch (error) {
useDefaultData()
}
} else {
useDefaultData()
}
4. 避免不必要的请求
// ✅ 好的做法
if (needData && token) {
await api.getData()
}
// ❌ 不好的做法
await api.getData() // 无论是否需要都请求
🔧 相关修改
其他可能需要检查的地方
如果项目中还有其他在应用启动时调用的接口,也需要检查是否需要 token:
-
检查
main.js的mounted钩子- 确保所有接口调用都检查了 token
-
检查
App.vue的mounted钩子- 确保没有未登录时调用需要认证的接口
-
检查路由守卫
- 确保路由守卫正确处理未登录的情况
-
检查 Vuex actions
- 确保需要认证的 actions 都检查了 token
📝 总结
修复的问题
- ✅ 未登录时不再调用需要认证的接口
- ✅ 避免了接口报错
- ✅ 提供了优雅的降级方案
- ✅ 改善了用户体验
代码改进
- 更健壮:双重检查确保不会在未登录时调用接口
- 更友好:即使接口失败也能正常显示默认标题
- 更清晰:代码逻辑更容易理解和维护
未登录接口调用问题已修复! 🎉
现在系统会智能判断是否已登录,只在必要时调用后端接口。