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

308 lines
7.4 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.
# 前端Token API迁移指南
## 📋 概述
TokenController接口已经从POST请求体传递token的方式优化为GET请求头传递token的标准方式。如果前端需要使用这些接口,请参考以下迁移指南。
## ✅ 当前状态
经过检查,前端代码中**没有直接使用**以下接口:
- `/token/user-info`
- `/token/username`
- `/token/validate`
前端主要使用的是AuthController中的接口:
- `/auth/user/info` - 获取用户信息
- `/auth/username` - 获取用户名
- `/auth/validateToken` - 验证Token
因此,**本次优化不需要修改前端代码**。
## 📚 接口使用指南(如果将来需要)
### 1. 获取用户信息
#### 旧方式(已废弃)
```typescript
// ❌ 不推荐:POST请求,token在请求体中
const response = await http.post('/token/user-info', {
token: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...'
})
```
#### 新方式(推荐)
```typescript
// ✅ 推荐:GET请求,token在请求头中(自动添加)
const response = await http.get('/token/user-info')
// 或者手动指定token(特殊场景)
const response = await http.get('/token/user-info', {
headers: {
'Authorization': `Bearer ${token}`
}
})
```
### 2. 获取用户名
#### 旧方式(已废弃)
```typescript
// ❌ 不推荐
const response = await http.post('/token/username', {
token: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...'
})
```
#### 新方式(推荐)
```typescript
// ✅ 推荐
const response = await http.get('/token/username')
```
### 3. 验证Token
#### 旧方式(已废弃)
```typescript
// ❌ 不推荐
const response = await http.post('/token/validate', {
token: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...'
})
```
#### 新方式(推荐)
```typescript
// ✅ 推荐
const response = await http.get('/token/validate')
```
## 🔧 HTTP请求工具配置
### 确保请求拦截器自动添加Token
大多数项目的HTTP工具已经配置了自动添加Authorization请求头的拦截器:
```typescript
// 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 }
```
### 如果项目还没有配置,请添加以下代码
```typescript
// 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的接口,可以创建以下服务:
```typescript
// 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中的接口,因为它们提供了更完整的功能:
```typescript
// 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存储在正确的位置:
```typescript
// 登录成功后存储token
localStorage.setItem('access_token', response.accessToken)
// 登出时清除token
localStorage.removeItem('access_token')
```
### 2. Token格式
确保token以正确的格式发送:
```
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
```
### 3. 错误处理
处理token相关的错误:
```typescript
try {
const userInfo = await tokenApi.getUserInfo()
} catch (error) {
if (error.response?.status === 401) {
// Token无效或过期
console.error('Token无效,请重新登录')
// 跳转到登录页
router.push('/login')
}
}
```
### 4. Token刷新
实现token自动刷新机制:
```typescript
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错误
这次优化使后端接口更加标准化和安全,为将来的扩展打下了良好的基础!