文字游戏
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.
 
 
 
 
 

7.6 KiB

API 集成指南

概述

项目已完整配置 axios,包括请求拦截器、响应拦截器和 API 服务层。

文件结构

src/api/
├── index.ts          # axios 实例配置(请求/响应拦截器)
└── auth.ts           # 登录相关 API 接口定义

核心概念

1. axios 实例配置 (src/api/index.ts)

// 创建 axios 实例
const instance = axios.create({
  baseURL: 'http://localhost:3000/api',  // 从环境变量读取
  timeout: 10000
})

请求拦截器:自动在请求头添加 Authorization 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,  // 成功时返回 data
  (error) => {
    if (error.response?.status === 401) {
      // Token 过期,清除登录状态并跳转到登录页
    }
  }
)

2. API 服务层 (src/api/auth.ts)

定义所有 API 接口和类型:

// 定义请求/响应类型
export interface LoginRequest {
  username: string
  password: string
}

export interface LoginResponse {
  code: number
  message: string
  data: {
    token: string
    user: User
  }
}

// 定义 API 接口
export const loginApi = (credentials: LoginRequest): Promise<LoginResponse> => {
  return http.post('/auth/login', credentials)
}

3. 状态管理 (src/stores/auth.ts)

在 Pinia store 中调用 API:

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)
      localStorage.setItem('user', JSON.stringify(user.value))
      
      return true
    }
  } catch (error) {
    console.error('登录失败:', error)
    return false
  }
}

登录流程详解

前端请求流程

1. 用户在登录页输入用户名和密码
   ↓
2. 点击"登录"按钮调用 handleLogin()
   ↓
3. authStore.login(username, password) 被调用
   ↓
4. loginApi({ username, password }) 发送 HTTP 请求
   ↓
5. axios 拦截器处理(添加 headers 等)
   ↓
6. 发送 POST /auth/login 请求到后端

后端需要返回的数据格式

{
  "code": 200,
  "message": "登录成功",
  "data": {
    "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
    "user": {
      "id": "1",
      "username": "admin",
      "email": "admin@example.com",
      "role": "admin"
    }
  }
}

字段说明:

  • code: HTTP 状态码(200 表示成功)
  • message: 返回消息
  • data.token: JWT token,用于后续请求认证
  • data.user: 用户信息对象
    • id: 用户 ID
    • username: 用户名
    • email: 邮箱
    • role: 用户角色(admin 或 user)

环境配置

.env.development (开发环境)

VITE_API_URL=http://localhost:3000/api

.env.production (生产环境)

VITE_API_URL=https://api.example.com/api

在代码中获取环境变量

const baseURL = import.meta.env.VITE_API_URL || 'http://localhost:3000/api'

使用示例

1. 调用登录 API

import { loginApi } from '@/api/auth'

const response = await loginApi({
  username: 'admin',
  password: '123456'
})

if (response.code === 200) {
  console.log('登录成功,用户信息:', response.data.user)
  console.log('Token:', response.data.token)
}

2. 在组件中使用 store

<script setup lang="ts">
import { useAuthStore } from '@/stores/auth'

const authStore = useAuthStore()

const login = async () => {
  const success = await authStore.login('admin', '123456')
  if (success) {
    // 登录成功,跳转
    router.push('/admin/dashboard')
  }
}
</script>

3. 创建新的 API 接口

src/api/ 中创建新文件,如 users.ts

import http from './index'

export interface User {
  id: number
  username: string
  email: string
  role: string
}

// 获取用户列表
export const getUsersApi = (page: number, limit: number) => {
  return http.get('/users', {
    params: { page, limit }
  })
}

// 创建用户
export const createUserApi = (data: User) => {
  return http.post('/users', data)
}

// 更新用户
export const updateUserApi = (id: number, data: Partial<User>) => {
  return http.put(`/users/${id}`, data)
}

// 删除用户
export const deleteUserApi = (id: number) => {
  return http.delete(`/users/${id}`)
}

错误处理

全局错误处理

axios 响应拦截器已处理以下情况:

状态码 处理方式
401 Token 过期,清除登录状态,跳转到登录页
其他 4xx/5xx 返回错误信息
网络错误 返回"网络错误"提示

在组件中处理错误

try {
  const response = await loginApi({ username, password })
  // 处理成功
} catch (error: any) {
  ElMessage.error(error?.message || '登录失败')
}

请求示例

POST 请求 (登录)

// 请求
POST /api/auth/login
Content-Type: application/json
Authorization: Bearer <token>

{
  "username": "admin",
  "password": "123456"
}

// 响应
{
  "code": 200,
  "message": "登录成功",
  "data": {
    "token": "...",
    "user": { ... }
  }
}

GET 请求 (获取列表)

// 请求
GET /api/users?page=1&limit=10
Authorization: Bearer <token>

// 响应
{
  "code": 200,
  "message": "成功",
  "data": {
    "items": [...],
    "total": 100
  }
}

PUT 请求 (更新)

// 请求
PUT /api/users/1
Content-Type: application/json
Authorization: Bearer <token>

{
  "username": "new_name",
  "email": "new@email.com"
}

// 响应
{
  "code": 200,
  "message": "更新成功",
  "data": { ... }
}

常见问题

Q: Token 过期怎么处理?

A: 后端返回 401 时,拦截器会自动清除 token 并跳转到登录页。

Q: 如何添加其他请求头?

A: 修改 src/api/index.ts 中的拦截器:

instance.interceptors.request.use((config) => {
  config.headers['Custom-Header'] = 'value'
  return config
})

Q: 如何处理超时?

A: 已在 axios 配置中设置 timeout: 10000(10秒)。修改 src/api/index.ts 中的 timeout 值。

Q: 如何调用 API 时显示加载状态?

A: 在组件中使用 loading ref:

const loading = ref(false)
loading.value = true
try {
  const response = await loginApi(...)
} finally {
  loading.value = false
}

集成后端步骤

  1. 启动后端服务

    # 后端服务应该运行在 http://localhost:3000
    
  2. 更新 API 地址 (如果不同)

    修改 .env.development 中的 VITE_API_URL
    
  3. 确保后端返回正确格式

    {
      "code": 200,
      "message": "...",
      "data": { ... }
    }
    
  4. 测试登录流程

  5. 检查 Token 存储

    • 打开浏览器开发者工具 → Application → LocalStorage
    • 应该看到 auth_tokenuser 字段

下一步

  • 集成后端登录接口
  • 添加用户列表 API (src/api/users.ts)
  • 添加产品 API (src/api/products.ts)
  • 添加订单 API (src/api/orders.ts)
  • 实现 token 刷新机制
  • 添加错误日志上报