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