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

8.0 KiB
Raw Blame History

未登录接口调用问题修复

🔍 问题描述

错误现象

在用户未登录时,sys_parameter/key 接口被调用,因为没有 token 导致接口报错。

错误原因

demo-project/src/main.jsmounted 钩子中,无条件调用了 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接口报错 ❌

解决方案

方案:只在已登录时调用接口

核心思路

  1. 在调用 getSysTitle 前检查是否已登录(是否有 token
  2. 已登录:调用接口获取系统标题
  3. 未登录:直接使用默认标题

修改 1demo-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 管理系统'
  }
}

修改 2src/store/app.jsgetSysTitle 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

  1. 检查 main.jsmounted 钩子

    • 确保所有接口调用都检查了 token
  2. 检查 App.vuemounted 钩子

    • 确保没有未登录时调用需要认证的接口
  3. 检查路由守卫

    • 确保路由守卫正确处理未登录的情况
  4. 检查 Vuex actions

    • 确保需要认证的 actions 都检查了 token

📝 总结

修复的问题

  • 未登录时不再调用需要认证的接口
  • 避免了接口报错
  • 提供了优雅的降级方案
  • 改善了用户体验

代码改进

  • 更健壮:双重检查确保不会在未登录时调用接口
  • 更友好:即使接口失败也能正常显示默认标题
  • 更清晰:代码逻辑更容易理解和维护

未登录接口调用问题已修复! 🎉

现在系统会智能判断是否已登录,只在必要时调用后端接口。