文字游戏
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

508 lines
11 KiB

2 weeks ago
# API 集成完整指南
你好!现在项目已经完全配置好了 axios 和 API 层。以下是完整的说明。
## 🎯 快速概览
### 已为你完成的工作
**Axios 配置** - 完整的 HTTP 客户端配置
**API 服务层** - 登录 API 接口定义
**认证 Store** - 与后端 API 集成的状态管理
**登录页面** - 支持异步 API 调用
**环境配置** - 开发和生产环境变量
**详细文档** - API 集成指南和后端示例
## 📁 项目结构
```
src/
├── api/
│ ├── index.ts ← axios 实例(请求/响应拦截器)
│ └── auth.ts ← 登录 API 接口(可扩展)
├── stores/
│ └── auth.ts ← 认证状态(调用 API)
├── views/
│ └── LoginView.vue ← 登录页面(异步登录)
└── ...
root/
├── .env.development ← 开发环境配置
├── .env.production ← 生产环境配置
├── API_INTEGRATION_GUIDE.md ← API 集成详细指南
├── BACKEND_API_EXAMPLE.md ← 后端实现参考
└── ...
```
## 🔄 工作流程
### 1️⃣ 用户登录流程
```
用户输入用户名和密码
点击"登录"按钮
LoginView.vue 调用 authStore.login(username, password)
authStore 调用 loginApi({ username, password })
axios 发送 POST /api/auth/login 请求
axios 拦截器处理:
- 添加 Authorization 头
- 处理错误响应
后端返回 JSON 响应
前端解析 response.data(自动由拦截器处理)
保存 token 和 user 到 localStorage
路由跳转到仪表板
```
### 2️⃣ 后续请求流程
```
任何组件需要调用 API
导入 API 函数(如 getUsersApi)
await getUsersApi()
axios 请求拦截器自动添加 Authorization: Bearer <token>
后端验证 token
后端返回数据
axios 响应拦截器处理(提取 data)
组件接收数据
```
## 💻 代码实现细节
### axios 实例 (`src/api/index.ts`)
```typescript
import axios from 'axios'
const instance = axios.create({
baseURL: import.meta.env.VITE_API_URL || 'http://localhost:3000/api',
timeout: 10000
})
// 请求拦截器 - 自动添加 token
instance.interceptors.request.use((config) => {
const token = localStorage.getItem('auth_token')
if (token) {
config.headers.Authorization = `Bearer ${token}`
}
return config
})
// 响应拦截器 - 处理错误和 token 过期
instance.interceptors.response.use(
(response) => response.data, // ← 返回 response.data
(error) => {
if (error.response?.status === 401) {
// token 过期,清除并跳转
localStorage.removeItem('auth_token')
window.location.href = '/login'
}
return Promise.reject(error)
}
)
export default instance
```
**关键点:**
1. 所有请求自动添加 `Authorization: Bearer <token>`
2. 所有响应自动提取 `response.data`
3. 401 错误自动清除 token 并跳转
### API 接口定义 (`src/api/auth.ts`)
```typescript
import http from './index'
export interface LoginRequest {
username: string
password: string
}
export interface LoginResponse {
code: number
message: string
data: {
token: string
user: User
}
}
export const loginApi = (credentials: LoginRequest): Promise<LoginResponse> => {
return http.post('/auth/login', credentials)
}
```
**使用方式:**
```typescript
const response = await loginApi({ username: 'admin', password: '123456' })
// response.code === 200
// response.data.token
// response.data.user
```
### 认证 Store (`src/stores/auth.ts`)
```typescript
export const useAuthStore = defineStore('auth', () => {
const login = async (username: string, password: string): Promise<boolean> => {
try {
const response = await loginApi({ username, password })
if (response.code === 200 && response.data) {
token.value = response.data.token
user.value = response.data.user
localStorage.setItem('auth_token', token.value)
return true
}
} catch (error) {
console.error('登录失败:', error)
return false
}
}
return { login, logout, user, token, isAuthenticated }
})
```
### 登录页面 (`src/views/LoginView.vue`)
```typescript
const handleLogin = async () => {
loading.value = true
try {
// 调用异步登录
const success = await authStore.login(username.value, password.value)
if (success) {
ElMessage.success('登录成功')
router.push('/admin/dashboard')
} else {
ElMessage.error('登录失败')
}
} catch (error: any) {
ElMessage.error(error?.message || '登录出错')
} finally {
loading.value = false
}
}
```
## 🛠 后端 API 需要返回什么?
### 登录接口
**端点:** `POST /api/auth/login`
**请求:**
```json
{
"username": "admin",
"password": "123456"
}
```
**响应格式(必须严格按照):**
```json
{
"code": 200,
"message": "登录成功",
"data": {
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"user": {
"id": "1",
"username": "admin",
"email": "admin@example.com",
"role": "admin"
}
}
}
```
**关键点:**
- `code` 必须是 200 表示成功
- `data.token` 是 JWT token,后续请求在 `Authorization: Bearer <token>` 中使用
- `data.user` 必须包含至少 `id, username, email, role` 字段
## 📝 添加更多 API 接口
### 例子:用户列表 API
1. **在 `src/api/` 中创建 `users.ts`:**
```typescript
import http from './index'
export interface User {
id: number
username: string
email: string
role: string
}
export interface UsersResponse {
code: number
message: string
data: {
items: User[]
total: number
}
}
// 获取用户列表
export const getUsersApi = (
page: number = 1,
limit: number = 10
): Promise<UsersResponse> => {
return http.get('/users', {
params: { page, limit }
})
}
// 创建用户
export const createUserApi = (data: User): Promise<any> => {
return http.post('/users', data)
}
// 更新用户
export const updateUserApi = (id: number, data: Partial<User>): Promise<any> => {
return http.put(`/users/${id}`, data)
}
// 删除用户
export const deleteUserApi = (id: number): Promise<any> => {
return http.delete(`/users/${id}`)
}
```
2. **在组件中使用:**
```typescript
import { getUsersApi } from '@/api/users'
const users = ref([])
const loading = ref(false)
const fetchUsers = async () => {
loading.value = true
try {
const response = await getUsersApi(1, 10)
if (response.code === 200) {
users.value = response.data.items
}
} catch (error) {
ElMessage.error('获取用户列表失败')
} finally {
loading.value = false
}
}
onMounted(() => {
fetchUsers()
})
```
## 🌐 环境配置
### 开发环境 (`.env.development`)
```
VITE_API_URL=http://localhost:3000/api
```
### 生产环境 (`.env.production`)
```
VITE_API_URL=https://api.example.com/api
```
### 在代码中使用
```typescript
const baseURL = import.meta.env.VITE_API_URL
console.log(baseURL) // 自动根据环境选择
// 或直接在 axios 配置中
baseURL: import.meta.env.VITE_API_URL || 'http://localhost:3000/api'
```
## 🧪 测试步骤
### 1. 启动后端服务
```bash
# Node.js Express 示例
node server.js
# 或 Python Flask 示例
python app.py
# 或你自己的后端服务
```
### 2. 验证后端在运行
访问 `http://localhost:3000/api/auth/login` (应该看到 404 或错误,说明服务在运行)
### 3. 使用 cURL 测试登录
```bash
curl -X POST http://localhost:3000/api/auth/login \
-H "Content-Type: application/json" \
-d '{"username":"admin","password":"123456"}'
```
应该返回:
```json
{
"code": 200,
"message": "登录成功",
"data": {
"token": "...",
"user": {...}
}
}
```
### 4. 启动前端
```bash
npm run dev
```
### 5. 在前端登录
- 访问 http://localhost:5173
- 输入用户名和密码
- 点击登录
- 如果成功,应该跳转到仪表板
### 6. 检查浏览器开发者工具
- **Network 标签:** 查看请求和响应
- **Application 标签:** 查看 localStorage 中的 `auth_token`
- **Console 标签:** 查看是否有错误
## 🔒 安全建议
1. **始终使用 HTTPS** (生产环境)
2. **密码必须加密存储** (使用 bcrypt 等)
3. **使用 JWT 令牌** 而不是 session
4. **设置合理的 token 过期时间** (如 7 天)
5. **实现 token 刷新机制** (可选但推荐)
6. **验证 CORS 配置** 只允许特定域名
7. **记录所有登录尝试** 用于审计
8. **使用速率限制** 防止暴力破解
## 常见问题
### Q: 如何在其他组件中获取当前用户?
```typescript
import { useAuthStore } from '@/stores/auth'
const authStore = useAuthStore()
console.log(authStore.user) // 当前用户
console.log(authStore.token) // 当前 token
```
### Q: 如何处理 token 刷新?
参考 `src/api/auth.ts` 中已定义的 `refreshTokenApi` 函数,在响应拦截器中实现 token 刷新逻辑。
### Q: 如何在请求中添加其他头信息?
```typescript
// 在 src/api/index.ts 中修改请求拦截器
instance.interceptors.request.use((config) => {
const token = localStorage.getItem('auth_token')
if (token) {
config.headers.Authorization = `Bearer ${token}`
}
// 添加其他头
config.headers['X-Custom-Header'] = 'value'
return config
})
```
### Q: 如何处理超时错误?
```typescript
const login = async () => {
try {
await authStore.login(username, password)
} catch (error: any) {
if (error.code === 'ECONNABORTED') {
ElMessage.error('请求超时,请检查网络')
} else {
ElMessage.error(error.message)
}
}
}
```
### Q: 前后端如何联调?
1. 后端启动在 http://localhost:3000
2. 前端启动在 http://localhost:5173
3. 确保 `.env.development``VITE_API_URL=http://localhost:3000/api`
4. 后端需要配置 CORS 允许 http://localhost:5173 访问
### Q: CORS 错误怎么解决?
后端需要配置 CORS:
**Express 示例:**
```javascript
const cors = require('cors')
app.use(cors({
origin: 'http://localhost:5173',
credentials: true
}))
```
**Flask 示例:**
```python
from flask_cors import CORS
CORS(app, resources={r"/api/*": {"origins": "http://localhost:5173"}})
```
## 📚 相关文档
- [API 集成详细指南](./API_INTEGRATION_GUIDE.md) - 完整的 API 使用说明
- [后端 API 实现参考](./BACKEND_API_EXAMPLE.md) - Node.js/Python 后端示例代码
- [项目总结](./PROJECT_SUMMARY.md) - 整个项目的概览
## 🎉 总结
你现在有:
✅ 完整的 axios 配置(请求/响应拦截器)
✅ API 服务层架构
✅ 登录示例(已与后端集成)
✅ 完整的类型定义 (TypeScript)
✅ 环境变量配置
✅ 详细的文档和后端示例
**下一步:**
1. 启动你的后端服务,确保监听 3000 端口
2. 实现后端的 `/api/auth/login` 接口,返回上述格式的 JSON
3. 运行 `npm run dev` 启动前端
4. 测试登录功能
有任何问题,请参考文档或查看相关代码注释!🚀