Skip to content

故障处理日志

本章节记录系统故障及其修复过程,供后续参考。


2026-01-17:官网 Admin 后台长时间未操作显示空数据

问题描述

用户反馈:官网 Admin 后台长时间不登录后,页面显示空数据,需要刷新或重新登录才能恢复。

表现

  • 统计卡片全部显示 0
  • 用户列表为空
  • 服务配置列表为空
  • 无任何错误提示

根因分析

问题本质:JWT Token 过期后,前端未正确处理 API 返回的 401 错误。

详细链路

  1. admin_token 使用通用的 signUserToken(),有效期只有 15 分钟
  2. Cookie 的 maxAge 设置的是 24 小时,导致 Cookie 还在但 Token 已过期
  3. 前端 middleware 只检查 Cookie 是否存在和格式,不验证 Token 是否过期
  4. API 返回 401 错误后,前端只是 console.error 打印日志,没有跳转登录页
  5. 页面保持空数据状态(statsusers 使用默认空值)

相关文件

  • server/utils/jwt.ts:Token 配置 accessTokenExpiry: '15m'
  • middleware/admin.ts:只检查 Cookie 存在性
  • pages/admin/index.vue:API 调用的 catch 块未处理 401

解决方案

1. 为 Admin 创建专用长效 Token(7天)

typescript
// server/api/admin/login.post.ts
const ADMIN_TOKEN_EXPIRY = '7d';

const signAdminToken = (user: any): string => {
    return jwt.sign({
        id: user.id,
        user_id: user.id,
        username: user.username,
        name: user.name,
        role: user.role,
        type: 'admin'
    }, secret, { expiresIn: ADMIN_TOKEN_EXPIRY });
};
typescript
setCookie(event, 'admin_token', token, {
    httpOnly: false,
    maxAge: 60 * 60 * 24 * 7, // 7 天
    // ...
});

3. 添加 401 错误自动跳转登录

javascript
// pages/admin/index.vue
const handleApiError = (e) => {
  if (e?.status === 401 || e?.statusCode === 401) {
    console.warn('[Admin] Token 已过期,跳转登录...');
    const adminToken = useCookie('admin_token');
    adminToken.value = null;
    navigateTo('/admin/login');
    return true;
  }
  return false;
};

// 在所有 API 调用的 catch 块中使用
try {
  // ...
} catch (e) {
  if (!handleApiError(e)) {
    console.error('Failed to fetch:', e);
  }
}

修改文件

文件修改内容
server/api/admin/login.post.ts创建 signAdminToken() 函数,7天有效期
pages/admin/index.vue添加 handleApiError() 函数处理 401

验证方式

  1. 登录 Admin 后台
  2. 等待 15 分钟后刷新页面(或手动清除 token)
  3. 应自动跳转到登录页,而非显示空数据

预防措施

  1. 所有管理后台 API 调用都应包含 401 错误处理
  2. Token 有效期 应与业务场景匹配:
    • 普通用户:15分钟(安全优先)
    • 管理后台:7天(便利优先)
  3. 考虑添加 Token 过期提示,而非静默失败

2026-01-17:Admin 登录后闪回登录页(附加问题)

问题描述

在修复上述"空数据"问题后,发现新问题:登录成功后页面短暂跳转到 /admin,随即闪回到 /admin/login

表现

  • 登录请求成功(服务器日志显示 "Login successful")
  • Token 正确写入 Cookie
  • 页面进入后台后立即闪回登录页
  • 控制台显示 [Admin] Token 已过期,跳转登录...

根因分析

问题本质:新签发的 Admin Token 使用了 type: 'admin',但验证函数检查的是 type === 'access'

详细链路

  1. signAdminToken() 签发的 Token payload 包含 type: 'admin'
  2. verifyAccessToken() 第 65 行检查 if (decoded.type !== 'access') return null
  3. Token 验证失败,API 返回 401
  4. 前端 handleApiError() 捕获 401,触发跳转登录

关键代码

typescript
// server/utils/jwt.ts - 第 62-71 行
export const verifyAccessToken = (token: string) => {
    try {
        const decoded = jwt.verify(token, getSecret());
        if (decoded.type !== 'access') {  // ← 这里要求 type 必须是 'access'
            return null;
        }
        return decoded;
    } catch (e) {
        return null;
    }
};

解决方案

将 Admin Token 的 type'admin' 改为 'access',保持与验证逻辑兼容:

typescript
// server/api/admin/login.post.ts
const signAdminToken = (user: any): string => {
    return jwt.sign({
        id: user.id,
        user_id: user.id,
        username: user.username,
        name: user.name,
        role: user.role,
        type: 'access'  // ← 与 verifyAccessToken 验证逻辑保持一致
    }, secret, { expiresIn: ADMIN_TOKEN_EXPIRY });
};

经验教训

  1. JWT Token 类型检查:签发新类型 Token 时,必须确认验证函数是否兼容
  2. 端到端测试:修改认证逻辑后,必须完整测试登录→API调用→登出流程
  3. 日志辅助定位:控制台输出 Token 已过期,跳转登录 虽然误导(实际是 type 不匹配),但帮助定位到 401 触发点

记录人:AI Agent
修复时间:2026-01-17 23:45