Files
happy-life-star/FRONTEND_TOKEN_API_MIGRATION_GUIDE.md
T
2025-10-13 10:43:08 +08:00

7.4 KiB
Raw Blame History

前端Token API迁移指南

📋 概述

TokenController接口已经从POST请求体传递token的方式优化为GET请求头传递token的标准方式。如果前端需要使用这些接口,请参考以下迁移指南。

当前状态

经过检查,前端代码中没有直接使用以下接口:

  • /token/user-info
  • /token/username
  • /token/validate

前端主要使用的是AuthController中的接口:

  • /auth/user/info - 获取用户信息
  • /auth/username - 获取用户名
  • /auth/validateToken - 验证Token

因此,本次优化不需要修改前端代码

📚 接口使用指南(如果将来需要)

1. 获取用户信息

旧方式(已废弃)

// ❌ 不推荐:POST请求,token在请求体中
const response = await http.post('/token/user-info', {
  token: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...'
})

新方式(推荐)

// ✅ 推荐:GET请求,token在请求头中(自动添加)
const response = await http.get('/token/user-info')

// 或者手动指定token(特殊场景)
const response = await http.get('/token/user-info', {
  headers: {
    'Authorization': `Bearer ${token}`
  }
})

2. 获取用户名

旧方式(已废弃)

// ❌ 不推荐
const response = await http.post('/token/username', {
  token: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...'
})

新方式(推荐)

// ✅ 推荐
const response = await http.get('/token/username')

3. 验证Token

旧方式(已废弃)

// ❌ 不推荐
const response = await http.post('/token/validate', {
  token: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...'
})

新方式(推荐)

// ✅ 推荐
const response = await http.get('/token/validate')

🔧 HTTP请求工具配置

确保请求拦截器自动添加Token

大多数项目的HTTP工具已经配置了自动添加Authorization请求头的拦截器:

// utils/request.ts 或 utils/http.ts
import axios from 'axios'

const http = axios.create({
  baseURL: import.meta.env.VITE_API_BASE_URL,
  timeout: 10000
})

// 请求拦截器:自动添加Token
http.interceptors.request.use(
  (config) => {
    // 从localStorage获取token
    const token = localStorage.getItem('access_token')
    
    // 如果token存在,添加到请求头
    if (token) {
      config.headers.Authorization = `Bearer ${token}`
    }
    
    return config
  },
  (error) => {
    return Promise.reject(error)
  }
)

export { http }

如果项目还没有配置,请添加以下代码

// 1. 在请求拦截器中添加token
http.interceptors.request.use((config) => {
  const token = localStorage.getItem('access_token')
  if (token && !config.headers.Authorization) {
    config.headers.Authorization = `Bearer ${token}`
  }
  return config
})

// 2. 在响应拦截器中处理401错误
http.interceptors.response.use(
  (response) => response,
  async (error) => {
    if (error.response?.status === 401) {
      // Token过期或无效,跳转到登录页
      localStorage.removeItem('access_token')
      window.location.href = '/login'
    }
    return Promise.reject(error)
  }
)

📝 API服务封装示例

如果需要使用TokenController的接口,可以创建以下服务:

// services/token.ts
import { http } from '@/utils/request'
import type { UserInfo } from '@/types'

export const tokenApi = {
  /**
   * 获取用户信息
   * Token会自动从请求头中获取
   */
  getUserInfo(): Promise<UserInfo> {
    return http.get('/token/user-info')
  },

  /**
   * 获取用户名
   * Token会自动从请求头中获取
   */
  getUsername(): Promise<string> {
    return http.get('/token/username')
  },

  /**
   * 验证Token
   * Token会自动从请求头中获取
   */
  validateToken(): Promise<string> {
    return http.get('/token/validate')
  }
}

🎯 推荐使用AuthController接口

实际上,建议前端继续使用AuthController中的接口,因为它们提供了更完整的功能:

// services/auth.ts
import { http } from '@/utils/request'

export const authApi = {
  /**
   * 获取当前用户信息
   * 推荐使用这个接口而不是 /token/user-info
   */
  getUserInfo(): Promise<UserInfo> {
    return http.get('/auth/user/info')
  },

  /**
   * 获取用户名
   * 推荐使用这个接口而不是 /token/username
   */
  getUsername(): Promise<string> {
    return http.get('/auth/username')
  },

  /**
   * 验证Token
   * 推荐使用这个接口而不是 /token/validate
   */
  validateToken(): Promise<boolean> {
    return http.get('/auth/validateToken')
  }
}

🔍 接口对比

功能 TokenController AuthController 推荐使用
获取用户信息 GET /token/user-info GET /auth/user/info AuthController
获取用户名 GET /token/username GET /auth/username AuthController
验证Token GET /token/validate GET /auth/validateToken AuthController

推荐理由

  • AuthController接口功能更完整
  • 已经在项目中广泛使用
  • 有更好的错误处理和日志记录
  • 与认证流程集成更紧密

⚠️ 注意事项

1. Token存储位置

确保token存储在正确的位置:

// 登录成功后存储token
localStorage.setItem('access_token', response.accessToken)

// 登出时清除token
localStorage.removeItem('access_token')

2. Token格式

确保token以正确的格式发送:

Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...

3. 错误处理

处理token相关的错误:

try {
  const userInfo = await tokenApi.getUserInfo()
} catch (error) {
  if (error.response?.status === 401) {
    // Token无效或过期
    console.error('Token无效,请重新登录')
    // 跳转到登录页
    router.push('/login')
  }
}

4. Token刷新

实现token自动刷新机制:

http.interceptors.response.use(
  (response) => response,
  async (error) => {
    const originalRequest = error.config
    
    if (error.response?.status === 401 && !originalRequest._retry) {
      originalRequest._retry = true
      
      try {
        // 尝试刷新token
        const refreshToken = localStorage.getItem('refresh_token')
        const response = await authApi.refreshToken({ refreshToken })
        
        // 更新token
        localStorage.setItem('access_token', response.accessToken)
        
        // 重试原始请求
        originalRequest.headers.Authorization = `Bearer ${response.accessToken}`
        return http(originalRequest)
      } catch (refreshError) {
        // 刷新失败,跳转到登录页
        localStorage.clear()
        window.location.href = '/login'
        return Promise.reject(refreshError)
      }
    }
    
    return Promise.reject(error)
  }
)

总结

  1. 当前状态:前端代码不需要修改,因为没有使用TokenController接口
  2. 推荐做法:继续使用AuthController接口
  3. 如果需要使用TokenController
    • 使用GET方法
    • Token在请求头中自动传递
    • 确保HTTP工具配置了请求拦截器
  4. 最佳实践
    • Token存储在localStorage
    • 使用Bearer格式
    • 实现自动刷新机制
    • 处理401错误

这次优化使后端接口更加标准化和安全,为将来的扩展打下了良好的基础!