Files
admin_core/demo-project/未登录接口调用问题修复.md
张成 7e888970d3 1
2025-10-08 19:20:24 +08:00

388 lines
8.0 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 未登录接口调用问题修复
## 🔍 问题描述
### 错误现象
在用户未登录时,`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
## 📝 总结
### 修复的问题
- ✅ 未登录时不再调用需要认证的接口
- ✅ 避免了接口报错
- ✅ 提供了优雅的降级方案
- ✅ 改善了用户体验
### 代码改进
- **更健壮**:双重检查确保不会在未登录时调用接口
- **更友好**:即使接口失败也能正常显示默认标题
- **更清晰**:代码逻辑更容易理解和维护
---
**未登录接口调用问题已修复!** 🎉
现在系统会智能判断是否已登录,只在必要时调用后端接口。