初步完成了api实现和请求拦截器

This commit is contained in:
carry 2025-02-14 15:23:16 +08:00
parent 2259911a8f
commit 5efdf76388
4 changed files with 158 additions and 8 deletions

View File

@ -1,15 +1,30 @@
import axios from 'axios';
import apiClient from './axiosInstance';
import type { TokenResponse, HTTPValidationError } from './types';
const API_BASE_URL = '/api/auth';
const API_BASE_URL = '/auth';
export const authService = {
async login(username: string, password: string) {
const response = await axios.post(`${API_BASE_URL}/login`, { username, password });
return response.data;
async login(username: string, password: string): Promise<TokenResponse> {
try {
const response = await apiClient.post(`${API_BASE_URL}/login`, { username, password });
return response.data;
} catch (error: any) {
if (error.response?.data?.detail?.[0]?.msg) {
throw new Error(error.response.data.detail[0].msg);
}
throw new Error('Login failed');
}
},
async refreshToken(refreshToken: string) {
const response = await axios.post(`${API_BASE_URL}/refresh`, { refresh_token: refreshToken });
return response.data;
async refreshToken(refreshToken: string): Promise<TokenResponse> {
try {
const response = await apiClient.post(`${API_BASE_URL}/refresh`, { refresh_token: refreshToken });
return response.data;
} catch (error: any) {
if (error.response?.data?.detail?.[0]?.msg) {
throw new Error(error.response.data.detail[0].msg);
}
throw new Error('Token refresh failed');
}
}
};

67
src/api/axiosInstance.ts Normal file
View File

@ -0,0 +1,67 @@
import axios from 'axios';
import { authService } from './authService';
// 创建axios实例
const apiClient = axios.create({
baseURL: '/api',
headers: {
'Content-Type': 'application/json',
},
});
// 请求拦截器
apiClient.interceptors.request.use(
async (config) => {
// 从localStorage获取access_token
const accessToken = localStorage.getItem('access_token');
if (accessToken) {
config.headers.Authorization = `Bearer ${accessToken}`;
}
return config;
},
(error) => {
return Promise.reject(error);
}
);
// 响应拦截器
apiClient.interceptors.response.use(
(response) => response,
async (error) => {
const originalRequest = error.config;
// 如果401错误且不是刷新token的请求
if (error.response?.status === 401 && !originalRequest._retry) {
originalRequest._retry = true;
try {
// 获取refresh_token
const refreshToken = localStorage.getItem('refresh_token');
if (!refreshToken) {
throw new Error('No refresh token available');
}
// 刷新token
const { access_token, refresh_token } = await authService.refreshToken(refreshToken);
// 保存新token
localStorage.setItem('access_token', access_token);
localStorage.setItem('refresh_token', refresh_token);
// 重试原始请求
originalRequest.headers.Authorization = `Bearer ${access_token}`;
return apiClient(originalRequest);
} catch (refreshError) {
// 刷新token失败跳转到登录页
window.location.href = '/login';
return Promise.reject(refreshError);
}
}
return Promise.reject(error);
}
);
export default apiClient;

41
src/api/types.ts Normal file
View File

@ -0,0 +1,41 @@
export interface UserResponse {
id: number;
username: string;
role: UserRole;
description?: string;
created_at: string;
updated_at: string;
}
export interface UserCreate {
username: string;
password: string;
role?: UserRole;
description?: string;
}
export interface UserUpdate {
username?: string;
role?: UserRole;
description?: string;
}
export interface TokenResponse {
access_token: string;
refresh_token: string;
token_type: string;
access_token_exp: number;
refresh_token_exp: number;
}
export interface HTTPValidationError {
detail: ValidationError[];
}
export interface ValidationError {
loc: (string | number)[];
msg: string;
type: string;
}
export type UserRole = 'system_admin' | 'admin' | 'user';

27
src/api/userService.ts Normal file
View File

@ -0,0 +1,27 @@
import apiClient from './axiosInstance';
import type { UserResponse, UserCreate, UserUpdate } from './types';
const API_BASE_URL = '/users';
export const userService = {
async getUsers(page = 1, limit = 100, role?: string): Promise<UserResponse[]> {
const response = await apiClient.get(API_BASE_URL, {
params: { page, limit, role }
});
return response.data;
},
async createUser(userData: UserCreate): Promise<UserResponse> {
const response = await apiClient.post(API_BASE_URL, userData);
return response.data;
},
async updateUser(userId: number, userData: UserUpdate): Promise<UserResponse> {
const response = await apiClient.put(`${API_BASE_URL}/${userId}`, userData);
return response.data;
},
async deleteUser(userId: number): Promise<void> {
await apiClient.delete(`${API_BASE_URL}/${userId}`);
}
};