Axios多實例封裝

Axios多實例封裝方案

我將為您提供一個完整的Axios多實例封裝方案,包含基礎封裝、多實例管理和使用示例。

設計思路

  1. 創建基礎axios實例封裝,支持請求/響應攔截器
  2. 實現多實例管理器,支持不同API端點配置
  3. 提供統一的錯誤處理機制
  4. 支持請求取消功能
  5. 提供完整的類型定義(TypeScript)

實現代碼

1. 基礎封裝和類型定義

// types.ts
export interface RequestConfig {url: string;method?: 'get' | 'post' | 'put' | 'delete' | 'patch';data?: any;params?: any;headers?: Record<string, string>;timeout?: number;withCredentials?: boolean;
}export interface ResponseData<T = any> {data: T;status: number;statusText: string;headers: any;config: RequestConfig;
}export interface ApiError extends Error {config: RequestConfig;code?: string;request?: any;response?: ResponseData;
}export interface ApiInstance {request: <T = any>(config: RequestConfig) => Promise<ResponseData<T>>;get: <T = any>(url: string, params?: any, config?: Omit<RequestConfig, 'url' | 'method' | 'data'>) => Promise<ResponseData<T>>;post: <T = any>(url: string, data?: any, config?: Omit<RequestConfig, 'url' | 'method' | 'params'>) => Promise<ResponseData<T>>;put: <T = any>(url: string, data?: any, config?: Omit<RequestConfig, 'url' | 'method' | 'params'>) => Promise<ResponseData<T>>;delete: <T = any>(url: string, params?: any, config?: Omit<RequestConfig, 'url' | 'method' | 'data'>) => Promise<ResponseData<T>>;patch: <T = any>(url: string, data?: any, config?: Omit<RequestConfig, 'url' | 'method' | 'params'>) => Promise<ResponseData<T>>;
}export interface ApiInstanceConfig {baseURL?: string;timeout?: number;headers?: Record<string, string>;withCredentials?: boolean;transformRequest?: (config: RequestConfig) => RequestConfig;transformResponse?: (response: ResponseData) => ResponseData;requestInterceptors?: Array<(config: RequestConfig) => RequestConfig | Promise<RequestConfig>>;responseInterceptors?: Array<(response: ResponseData) => ResponseData | Promise<ResponseData>>;errorInterceptors?: Array<(error: ApiError) => Promise<never>>;
}

2. 核心封裝類

// axios-instance.ts
import axios, { AxiosRequestConfig, AxiosResponse, AxiosError, CancelTokenSource } from 'axios';
import {RequestConfig,ResponseData,ApiError,ApiInstance,ApiInstanceConfig
} from './types';export class AxiosInstance implements ApiInstance {private instance: any;private cancelTokenSource: CancelTokenSource;constructor(config: ApiInstanceConfig = {}) {this.cancelTokenSource = axios.CancelToken.source();const axiosConfig: AxiosRequestConfig = {baseURL: config.baseURL,timeout: config.timeout || 30000,headers: {'Content-Type': 'application/json',...config.headers},withCredentials: config.withCredentials || false,cancelToken: this.cancelTokenSource.token};this.instance = axios.create(axiosConfig);// 請求攔截器this.instance.interceptors.request.use((axiosConfig: AxiosRequestConfig) => {let finalConfig: RequestConfig = {url: axiosConfig.url || '',method: axiosConfig.method as any,data: axiosConfig.data,params: axiosConfig.params,headers: axiosConfig.headers,timeout: axiosConfig.timeout,withCredentials: axiosConfig.withCredentials};// 應用自定義請求轉換if (config.transformRequest) {finalConfig = config.transformRequest(finalConfig);}// 應用請求攔截器if (config.requestInterceptors) {for (const interceptor of config.requestInterceptors) {finalConfig = interceptor(finalConfig);}}return {...axiosConfig,...finalConfig};},(error: AxiosError) => {const apiError: ApiError = {name: 'RequestError',message: error.message,config: error.config as RequestConfig,code: error.code,request: error.request};return Promise.reject(apiError);});// 響應攔截器this.instance.interceptors.response.use((response: AxiosResponse) => {const responseData: ResponseData = {data: response.data,status: response.status,statusText: response.statusText,headers: response.headers,config: response.config as RequestConfig};let finalResponse = responseData;// 應用響應攔截器if (config.responseInterceptors) {for (const interceptor of config.responseInterceptors) {finalResponse = interceptor(finalResponse);}}// 應用自定義響應轉換if (config.transformResponse) {finalResponse = config.transformResponse(finalResponse);}return finalResponse;},(error: AxiosError) => {const apiError: ApiError = {name: 'ResponseError',message: error.message,config: error.config as RequestConfig,code: error.code,request: error.request,response: error.response ? {data: error.response.data,status: error.response.status,statusText: error.response.statusText,headers: error.response.headers,config: error.response.config as RequestConfig} : undefined};// 應用錯誤攔截器if (config.errorInterceptors) {for (const interceptor of config.errorInterceptors) {return interceptor(apiError);}}return Promise.reject(apiError);});}async request<T = any>(config: RequestConfig): Promise<ResponseData<T>> {try {return await this.instance.request(config);} catch (error) {throw error as ApiError;}}get<T = any>(url: string, params?: any, config?: Omit<RequestConfig, 'url' | 'method' | 'data'>): Promise<ResponseData<T>> {return this.request<T>({url,method: 'get',params,...config});}post<T = any>(url: string, data?: any, config?: Omit<RequestConfig, 'url' | 'method' | 'params'>): Promise<ResponseData<T>> {return this.request<T>({url,method: 'post',data,...config});}put<T = any>(url: string, data?: any, config?: Omit<RequestConfig, 'url' | 'method' | 'params'>): Promise<ResponseData<T>> {return this.request<T>({url,method: 'put',data,...config});}delete<T = any>(url: string, params?: any, config?: Omit<RequestConfig, 'url' | 'method' | 'data'>): Promise<ResponseData<T>> {return this.request<T>({url,method: 'delete',params,...config});}patch<T = any>(url: string, data?: any, config?: Omit<RequestConfig, 'url' | 'method' | 'params'>): Promise<ResponseData<T>> {return this.request<T>({url,method: 'patch',data,...config});}// 取消當前實例的所有請求cancelAllRequests(message?: string): void {this.cancelTokenSource.cancel(message || 'Request canceled');// 創建新的cancel token用于后續請求this.cancelTokenSource = axios.CancelToken.source();this.instance.defaults.cancelToken = this.cancelTokenSource.token;}// 獲取當前cancel token,可用于特定請求的取消getCancelToken() {return this.cancelTokenSource.token;}
}

3. 多實例管理器

// api-manager.ts
import { AxiosInstance } from './axios-instance';
import { ApiInstanceConfig, ApiInstance } from './types';export class ApiManager {private instances: Map<string, AxiosInstance> = new Map();private static instance: ApiManager;private constructor() {}static getInstance(): ApiManager {if (!ApiManager.instance) {ApiManager.instance = new ApiManager();}return ApiManager.instance;}createInstance(name: string, config: ApiInstanceConfig = {}): AxiosInstance {if (this.instances.has(name)) {throw new Error(`API instance with name "${name}" already exists`);}const instance = new AxiosInstance(config);this.instances.set(name, instance);return instance;}getInstance(name: string): AxiosInstance {const instance = this.instances.get(name);if (!instance) {throw new Error(`API instance with name "${name}" not found`);}return instance;}removeInstance(name: string): void {this.instances.delete(name);}hasInstance(name: string): boolean {return this.instances.has(name);}getAllInstanceNames(): string[] {return Array.from(this.instances.keys());}// 取消所有實例的所有請求cancelAllRequests(message?: string): void {this.instances.forEach(instance => {instance.cancelAllRequests(message);});}
}// 導出單例
export const apiManager = ApiManager.getInstance();

4. 預設實例配置

// api-configs.ts
import { ApiInstanceConfig } from './types';// 認證攔截器
const authRequestInterceptor = (config: any) => {const token = localStorage.getItem('auth_token');if (token) {config.headers = config.headers || {};config.headers.Authorization = `Bearer ${token}`;}return config;
};// 通用響應攔截器 - 處理標準響應格式
const standardResponseInterceptor = (response: any) => {// 假設后端返回格式為 { code: number, data: any, message: string }if (response.data && typeof response.data === 'object') {if (response.data.code !== 0 && response.data.code !== 200) {throw new Error(response.data.message || 'Request failed');}// 返回數據部分return {...response,data: response.data.data};}return response;
};// 錯誤處理攔截器
const errorInterceptor = (error: any) => {if (error.response) {switch (error.response.status) {case 401:// 處理未授權localStorage.removeItem('auth_token');window.location.href = '/login';break;case 403:// 處理禁止訪問console.error('Permission denied');break;case 500:// 處理服務器錯誤console.error('Server error');break;default:console.error('Request error', error.message);}} else if (error.request) {console.error('Network error', error.message);} else {console.error('Request setup error', error.message);}return Promise.reject(error);
};// 主API配置
export const mainApiConfig: ApiInstanceConfig = {baseURL: process.env.REACT_APP_API_BASE_URL || 'https://api.example.com',timeout: 30000,headers: {'X-Requested-With': 'XMLHttpRequest'},requestInterceptors: [authRequestInterceptor],responseInterceptors: [standardResponseInterceptor],errorInterceptors: [errorInterceptor]
};// 認證API配置
export const authApiConfig: ApiInstanceConfig = {baseURL: process.env.REACT_APP_AUTH_API_URL || 'https://auth.example.com',timeout: 15000,headers: {'X-API-Source': 'web-frontend'},responseInterceptors: [standardResponseInterceptor],errorInterceptors: [errorInterceptor]
};// 第三方API配置
export const thirdPartyApiConfig: ApiInstanceConfig = {baseURL: 'https://api.thirdparty.com',timeout: 20000,transformResponse: (response) => {// 轉換第三方API的響應格式if (response.data && response.data.result) {return {...response,data: response.data.result};}return response;}
};

5. 使用示例

// api-instances.ts
import { apiManager } from './api-manager';
import { mainApiConfig, authApiConfig, thirdPartyApiConfig } from './api-configs';// 創建多個API實例
export const mainApi = apiManager.createInstance('main', mainApiConfig);
export const authApi = apiManager.createInstance('auth', authApiConfig);
export const thirdPartyApi = apiManager.createInstance('thirdParty', thirdPartyApiConfig);// 業務API函數
export const userApi = {// 獲取用戶信息getUser: (userId: number) => mainApi.get(`/users/${userId}`),// 更新用戶信息updateUser: (userId: number, data: any) => mainApi.put(`/users/${userId}`, data),// 獲取用戶列表getUsers: (params?: { page: number; limit: number }) => mainApi.get('/users', params)
};export const authService = {// 登錄login: (credentials: { email: string; password: string }) => authApi.post('/login', credentials),// 注冊register: (userData: any) => authApi.post('/register', userData),// 退出登錄logout: () => authApi.post('/logout')
};export const thirdPartyService = {// 獲取第三方數據getData: (id: string) => thirdPartyApi.get(`/data/${id}`),// 提交數據到第三方submitData: (data: any) => thirdPartyApi.post('/submit', data)
};// 取消所有請求(例如在路由切換時)
export const cancelAllRequests = (message?: string) => {apiManager.cancelAllRequests(message);
};

6. 在React組件中使用

// UserProfile.tsx
import React, { useState, useEffect } from 'react';
import { userApi, cancelAllRequests } from './api-instances';const UserProfile: React.FC<{ userId: number }> = ({ userId }) => {const [user, setUser] = useState<any>(null);const [loading, setLoading] = useState<boolean>(true);const [error, setError] = useState<string>('');useEffect(() => {const fetchUser = async () => {try {setLoading(true);setError('');const response = await userApi.getUser(userId);setUser(response.data);} catch (err: any) {setError(err.message || 'Failed to fetch user');} finally {setLoading(false);}};fetchUser();// 組件卸載時取消請求return () => {cancelAllRequests('Component unmounted');};}, [userId]);if (loading) return <div>Loading...</div>;if (error) return <div>Error: {error}</div>;return (<div><h1>{user.name}</h1><p>Email: {user.email}</p>{/* 更多用戶信息 */}</div>);
};export default UserProfile;

主要特性

  1. 多實例支持:可以創建多個Axios實例,每個實例有獨立的配置
  2. 類型安全:完整的TypeScript支持
  3. 攔截器鏈:支持請求/響應攔截器,支持異步攔截器
  4. 錯誤處理:統一的錯誤處理機制
  5. 請求取消:支持取消請求,避免內存泄漏
  6. 響應轉換:支持自定義響應數據轉換
  7. 單例管理:通過ApiManager統一管理所有實例

使用建議

  1. 根據業務模塊劃分不同的API實例
  2. 為不同后端服務創建獨立的實例
  3. 在路由切換時取消未完成的請求
  4. 使用攔截器統一處理認證、錯誤提示等通用邏輯
  5. 根據項目需求擴展配置選項

這個封裝方案提供了靈活而強大的Axios多實例管理能力,適合中大型前端項目使用。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/94759.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/94759.shtml
英文地址,請注明出處:http://en.pswp.cn/web/94759.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

為量化從業者提供免費穩定的股票數據源:免費股票數據API獲取實時數據、歷史數據與技術指標(含多語言代碼指南)實例代碼演示與API文檔說明

? 近年來&#xff0c;股票量化分析因其科學、系統的研究方法&#xff0c;日益成為市場熱點。而進入這一領域的首要步驟&#xff0c;正是獲取全面、準確的股票數據——無論是實時交易行情、歷史走勢記錄&#xff0c;還是企業財務與基本面信息&#xff0c;都是支撐量化策略的核心…

[Sync_ai_vid] UNet模型 | 音頻特征提取器(Whisper)

第2章&#xff1a;LatentSync UNet模型 在第1章&#xff1a;唇形同步推理流程中&#xff0c;我們了解到唇形同步推理流程如同電影導演&#xff0c;協調各"專家模塊"生成完美唇形同步視頻。 本章將深入解析這個"工作室"中最核心的專家——LatentSync UNet…

工業級TF卡NAND + 北京君正 + Rk瑞芯微的應用

目錄前言一&#xff1a;操作CS創世 SD NAND的常用命令1.查看SD設備2.掛載分區3.卸載分區4.分區管理5.格式化分區6.簡單讀寫二&#xff1a;SD底層協議簡要介紹三&#xff1a;對CS創世 SD NAND進行讀寫操作的三大方式1. 使用dd命令2. 使用塊設備的標準接口3. 使用ioctl產生系統調…

深入解析Java并發編程與單例模式

目錄 一、調度(四) 1.隨機調度大環境 二、鎖(二) 1.位置 2.無鎖阻塞 3.重入鎖 4.連續鎖 4.1措施 三、線程方法(二) 1.wait 2.notify 3.wait-notify指位后移 3.1可能時再檢查 3.1.1join(二) 3.1.1.1可能時再檢查死亡 四、單例模式 1.實現 1.1private構造器 1…

java通過redis簡單實現分布式鎖

目錄 一、簡介 二、代碼實現 1、maven添加依賴 2、核心邏輯代碼 3、使用方式 三、總結 一、簡介 我們知道在Java中可以通過關鍵字synchronized來防止并發引起的問題&#xff0c;而分布式中就需要考慮分布式鎖了&#xff0c;今天來講一個比較簡單的實現&#xff0c;通過re…

網絡編程--TCP/UDP Socket套接字

網絡編程 程序員主要操作應用層和傳輸層來實現網絡編程&#xff0c;也就是自己寫一個程序&#xff0c;讓這個程序可以使用網絡來通信&#xff0c;這個程序屬于應用層&#xff0c;實現通訊就需要獲取到傳輸層提供的服務 這就需要使用傳輸層提供的api UDP: 無連接&#xff0c;不可…

claude-code訂閱方案

Claude Code 訂閱方案對比 編寫日期&#xff1a;2025 年 08 月 20 日 &#x1f3f7;? 專業版 Pro ($20/月&#xff0c;$200/年) 主要特性 可用模型&#xff1a;Claude Sonnet 4&#xff08;Claude Opus 4成本太高&#xff0c;謹慎選擇&#xff09;適用場景&#xff1a;適合輕度…

146. LRU緩存

題目&#xff1a; 請你設計并實現一個滿足 LRU (最近最少使用) 緩存 約束的數據結構。 實現 LRUCache 類&#xff1a; LRUCache(int capacity) 以 正整數 作為容量 capacity 初始化 LRU 緩存 int get(int key) 如果關鍵字 key 存在于緩存中&#xff0c;則返回關鍵字的值&#x…

第二十節:3D文本渲染 - 字體幾何體生成與特效

第二十節&#xff1a;3D文本渲染 - 字體幾何體生成與特效 TextGeometry深度解析與高級文字效果實現1. 核心概念解析 1.1 3D文字渲染技術對比技術原理優點缺點TextGeometry將字體輪廓轉換為3D網格真實3D效果&#xff0c;支持材質性能開銷大&#xff0c;內存占用高Canvas紋理將文…

zzz‘sJava知識點概括總結

類型轉化 字符串&#xff1a;c語言&#xff1a;char Java&#xff1a;string 表達式值的類型由最高類型決定&#xff1a; 取值范圍&#xff1a;byte<short<int<long<float<double&#xff08;且運算時byte和short都是轉化為int類型進行計算防止數據溢出&…

SONiC 之 Testbed(2)Ansible

Ansible 是一款由 Red Hat 主導開發的 開源自動化工具&#xff0c;專注于 配置管理、應用部署、任務編排和IT自動化。它基于 無代理&#xff08;Agentless&#xff09;架構&#xff0c;通過 SSH&#xff08;默認&#xff09;或 WinRM 協議與目標設備通信&#xff0c;無需在被控…

瑞芯微RK3568與君正X2600e平臺Linux系統CS創世SD NAND應用全解析與驅動架構詳解

前言 今天就瑞芯微平臺和北京君正平臺下的linux系統中關于CS創世 SD NAND的使用做一些經驗的分享&#xff0c;如有不正&#xff0c;請批評指正&#xff1b; 采用的開發板是RK3568和x2600e&#xff0c;ubuntu版本是20.04&#xff0c;交叉編譯工具鏈是aarch64-linux-gnu-和mips…

深入解析 Flink Function

RichFunctionFunction只是個標記接口public interface Function extends java.io.Serializable {}RichFunction 的核心語義是為用戶定義的函數&#xff08;UDF&#xff09;提供生命周期管理和運行時上下文訪問的能力。任何一個普通的 Flink Function 接口&#xff08;例如 MapF…

JMeter —— 壓力測試

目錄 常用的性能指標 一、吞吐量類指標 二、響應時間類指標 三、資源利用率指標 JMeter 一、JMeter 簡介 二.下載安裝JMeter&#xff1a; 三.如何使用JMeter&#xff1a; 壓力測試考察當前軟硬件環境下系統所能承受的最大負荷并幫助找出系統瓶頸所在。壓測都是為了系統…

Transformer在哪?做了權重共享?

1、什么是權值共享權重共享是指在模型的不同層之間復?相同的參數。這可以減少模型的總體參數數量&#xff0c;并使得模型在訓練時更容易學習。2、在Transformer中的應用常見的做法是共享詞嵌入層&#xff08;embedding layer&#xff09;和輸出層&#xff08;output layer&…

將 agents 連接到 Elasticsearch 使用模型上下文協議 - docker

我們在之前的文章 “將 agents 連接到 Elasticsearch 使用模型上下文協議” 及 “使用 MCP 將代理連接到 Elasticsearch 并對索引進行查詢” 詳述了如何使用 Elasticsearch MCP server 來和我們的 Elasticsearch 進行對話。細心的開發者可能已經注意到我們的 Elasticsearch MCP…

Shell 編程基礎與實踐要點梳理

目錄 前言 一、認識 Shell 1.1 Shell 的定義與作用 1.2 Shell 解釋器 二、Shell 腳本入門 2.1 編寫 Shell 腳本 2.2 賦予執行權限與執行腳本 三、Shell 變量 3.1 變量定義與規則 3.2 變量使用與操作 3.3 變量類型 四、Shell 字符串 4.1 字符串定義方式 4.2 字符串…

Python自動化測試完整教程:pytest + selenium實戰

目錄 前言環境搭建pytest基礎教程selenium基礎教程pytest selenium實戰項目頁面對象模式(POM)測試報告生成持續集成配置最佳實踐和進階技巧總結 前言 自動化測試是現代軟件開發中不可或缺的一環。Python作為一門簡潔優雅的編程語言&#xff0c;配合pytest測試框架和seleniu…

APM 系列(一):Skywalking 與 Easyearch 集成

概述 SkyWalking 是一個開源的可觀測性平臺&#xff0c;用于收集、分析、聚合和可視化服務和云原生基礎設施的數據。SkyWalking 提供了一種簡單的方法&#xff0c;即使在云之間也能保持對分布式系統的清晰視圖。它是一個現代的 APM&#xff0c;專門為云原生、基于容器的分布式…

使用 AD 帳戶從 ASP.NET 8 容器登錄 SQL Server 的 Kerberos Sidecar

我最近在做一個項目,需要將一個 ASP.NET 8 Web API 應用程序容器化,該應用程序需要與本地運行的 SQL Server 數據庫進行通信。我們決定將 ASP.NET 8 容器定位到 Linux 系統,因此必須與運行在 Windows AD 域中的數據庫進行通信。 問題 我們之前的設置是使用 IIS 在 Windows …