Axios 深度解析:企业级 HTTP 客户端解决方案
Axios 深度解析:企业级 HTTP 客户端解决方案
Axios 是一个基于 Promise 的现代化 HTTP 客户端库,专为浏览器和 Node.js 设计。它已成为企业级应用开发的首选 HTTP 工具,因其强大的功能、简洁的 API 和出色的错误处理机制而备受青睐。
核心特性与架构设计
1.跨平台支持
- 浏览器端:使用 XMLHttpRequest
- Node.js 端:使用内置 http 模块
- 统一 API 简化多环境开发
2.Promise 驱动
axios.get('/api/users')
.then(response => handleData(response))
.catch(error => handleError(error));
3.拦截器机制
// 请求拦截器
axios.interceptors.request.use(config => {
config.headers.Authorization = `Bearer ${getToken()}`;
return config;
});
// 响应拦截器
axios.interceptors.response.use(
response => response,
error => {
if (error.response.status === 401) {
redirectToLogin();
}
return Promise.reject(error);
}
);
4.取消请求
const source = axios.CancelToken.source();
axios.get('/api/data', {
cancelToken: source.token
});
// 取消请求
source.cancel('Operation canceled by user');
Axios Request 深度剖析
请求配置对象
const config = {
// 请求目标 URL
url: '/api/users',
// 请求方法 (默认: 'get')
method: 'post',
// 基础 URL
baseURL: 'https://api.example.com',
// 请求头
headers: {'X-Custom-Header': 'value'},
// 请求参数 (URL 查询参数)
params: {
page: 1,
limit: 20
},
// 请求体数据 (POST/PUT/PATCH)
data: {
firstName: 'John',
lastName: 'Doe'
},
// 请求超时时间 (毫秒)
timeout: 5000,
// 跨域请求是否携带凭证
withCredentials: true,
// 响应数据类型 (默认: 'json')
responseType: 'json',
// 上传进度处理
onUploadProgress: progressEvent => {
const percent = Math.round(
(progressEvent.loaded * 100) / progressEvent.total
);
updateProgress(percent);
},
// 下载进度处理
onDownloadProgress: progressEvent => {
/* 处理下载进度 */
},
// 请求取消令牌
cancelToken: new CancelToken(cancel => {
/* 取消函数 */
}),
// 自定义序列化函数
paramsSerializer: params => {
return Qs.stringify(params, {arrayFormat: 'brackets'});
}
};
企业级请求最佳实践
1. 全局配置管理
// 创建企业级 Axios 实例
const apiClient = axios.create({
baseURL: process.env.API_BASE_URL,
timeout: 10000,
headers: {
'Content-Type': 'application/json',
'X-Client-Version': '1.0.0'
}
});
2. 请求工厂模式
// 企业级 API 请求工厂
export const createApiRequest = (endpoint, data = {}, method = 'get') => {
return apiClient({
url: endpoint,
method,
data: method !== 'get' ? data : undefined,
params: method === 'get' ? data : undefined
});
};
// 使用示例
const fetchUser = (userId) => createApiRequest(`/users/${userId}`);
const updateUser = (userId, data) =>
createApiRequest(`/users/${userId}`, data, 'put');
3. 自动重试机制
// 企业级重试拦截器
apiClient.interceptors.response.use(null, error => {
const config = error.config;
// 如果未设置重试次数,默认为 3
config.__retryCount = config.__retryCount || 0;
// 检查是否达到最大重试次数
if (config.__retryCount >= (config.retry || 3)) {
return Promise.reject(error);
}
// 增加重试计数器
config.__retryCount += 1;
// 创建新的 Promise 用于重试
const backoff = new Promise(resolve => {
setTimeout(() => resolve(), config.retryDelay || 1000);
});
// 重试请求
return backoff.then(() => apiClient(config));
});
Axios Response 深度剖析
响应对象结构
{
// 服务器返回的数据
data: {},
// HTTP 状态码
status: 200,
// HTTP 状态文本
statusText: 'OK',
// 响应头
headers: {
'content-type': 'application/json',
'content-length': '1024'
},
// Axios 请求配置
config: {},
// 底层请求对象
request: {}
}
企业级响应处理策略
1. 统一响应格式处理
// 企业级响应拦截器
apiClient.interceptors.response.use(response => {
// 标准化成功响应
return {
success: true,
status: response.status,
data: response.data,
headers: response.headers
};
}, error => {
// 标准化错误响应
if (error.response) {
// 服务器返回了错误响应 (4xx, 5xx)
return {
success: false,
status: error.response.status,
message: error.response.data?.message || 'Request failed',
errors: error.response.data?.errors || [],
headers: error.response.headers
};
} else if (error.request) {
// 请求已发出但无响应
return {
success: false,
message: 'No response received',
isNetworkError: true
};
} else {
// 请求配置错误
return {
success: false,
message: error.message
};
}
});
2. API 响应时间监控
// 性能监控拦截器
apiClient.interceptors.request.use(config => {
config.metadata = { startTime: performance.now() };
return config;
});
apiClient.interceptors.response.use(response => {
const duration = performance.now() - response.config.metadata.startTime;
logApiPerformance(response.config.url, duration);
return response;
}, error => {
if (error.config) {
const duration = performance.now() - error.config.metadata.startTime;
logApiPerformance(error.config.url, duration, true);
}
return Promise.reject(error);
});
3. 安全审计日志
// 安全审计拦截器
apiClient.interceptors.response.use(response => {
if (response.data?.sensitive) {
logSecurityEvent({
type: 'API_RESPONSE',
endpoint: response.config.url,
status: response.status,
dataHash: hashResponseData(response.data)
});
}
return response;
}, error => {
if (error.response?.status === 401 || error.response?.status === 403) {
logSecurityEvent({
type: 'AUTH_FAILURE',
endpoint: error.config.url,
status: error.response.status
});
}
return Promise.reject(error);
});
企业级 Axios 最佳实践
1.安全增强配置
// 安全强化配置
const secureAxios = axios.create({
timeout: 10000,
xsrfCookieName: 'XSRF-TOKEN',
xsrfHeaderName: 'X-XSRF-TOKEN',
httpAgent: new http.Agent({ keepAlive: true }),
httpsAgent: new https.Agent({
keepAlive: true,
rejectUnauthorized: true,
ciphers: 'TLS_AES_256_GCM_SHA384'
}),
maxRedirects: 5,
validateStatus: status => status >= 200 && status < 400
});
2.多实例策略
// 创建不同的 API 实例
const publicApi = axios.create({
baseURL: 'https://api.example.com/public'
});
const privateApi = axios.create({
baseURL: 'https://api.example.com/private',
headers: {
Authorization: `Bearer ${getAuthToken()}`
}
});
const fileUploadApi = axios.create({
baseURL: 'https://files.example.com',
headers: {
'Content-Type': 'multipart/form-data'
},
timeout: 30000
});
3.错误分类处理
// 企业级错误处理函数
const handleApiError = (error) => {
if (axios.isCancel(error)) {
console.log('Request canceled:', error.message);
return { type: 'CANCELED', message: error.message };
}
if (!error.response) {
return { type: 'NETWORK_ERROR', message: 'Network issue' };
}
const status = error.response.status;
const data = error.response.data;
switch (status) {
case 400:
return { type: 'BAD_REQUEST', errors: data.errors };
case 401:
refreshToken();
return { type: 'UNAUTHORIZED', message: 'Please reauthenticate' };
case 403:
return { type: 'FORBIDDEN', message: 'Insufficient permissions' };
case 404:
return { type: 'NOT_FOUND', message: 'Resource not found' };
case 429:
return { type: 'RATE_LIMITED', retryAfter: data.retryAfter };
case 500:
return { type: 'SERVER_ERROR', message: 'Internal server error' };
default:
return { type: 'UNKNOWN_ERROR', status, data };
}
};
4.文件上传下载
// 企业级文件上传
const uploadFile = (file, onProgress) => {
const formData = new FormData();
formData.append('file', file);
return apiClient.post('/upload', formData, {
headers: {
'Content-Type': 'multipart/form-data'
},
onUploadProgress: progressEvent => {
if (onProgress) {
const percent = Math.round(
(progressEvent.loaded * 100) / progressEvent.total
);
onProgress(percent);
}
}
});
};
// 企业级文件下载
const downloadFile = (fileId, fileName) => {
return apiClient.get(`/files/${fileId}`, {
responseType: 'blob'
}).then(response => {
const url = window.URL.createObjectURL(new Blob([response.data]));
const link = document.createElement('a');
link.href = url;
link.setAttribute('download', fileName);
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
});
};
Axios 在微服务架构中的应用
服务间通信
// 服务发现集成
const getServiceUrl = async (serviceName) => {
const registry = await serviceDiscovery.get(serviceName);
return `https://${registry.host}:${registry.port}`;
};
// 服务间请求
const callService = async (service, endpoint, data) => {
const baseURL = await getServiceUrl(service);
return axios.post(`${baseURL}${endpoint}`, data, {
headers: {
'X-Service-Request': 'true',
'X-Source-Service': 'user-service'
}
});
};
断路器模式实现
// 企业级断路器
class CircuitBreaker {
constructor(request, options = {}) {
this.request = request;
this.state = 'CLOSED';
this.failureCount = 0;
this.successCount = 0;
this.nextAttempt = Date.now();
this.options = {
failureThreshold: 3,
successThreshold: 2,
timeout: 5000,
...options
};
}
async fire() {
if (this.state === 'OPEN') {
if (this.nextAttempt <= Date.now()) {
this.state = 'HALF-OPEN';
} else {
throw new Error('Circuit is OPEN');
}
}
try {
const response = await this.request();
return this.success(response);
} catch (err) {
return this.fail(err);
}
}
success(response) {
if (this.state === 'HALF-OPEN') {
this.successCount++;
if (this.successCount > this.options.successThreshold) {
this.close();
}
}
return response;
}
fail(err) {
this.failureCount++;
if (this.failureCount >= this.options.failureThreshold) {
this.open();
}
throw err;
}
open() {
this.state = 'OPEN';
this.nextAttempt = Date.now() + this.options.timeout;
}
close() {
this.state = 'CLOSED';
this.failureCount = 0;
this.successCount = 0;
}
}
// 使用断路器包装 Axios 请求
const breaker = new CircuitBreaker(() =>
axios.get('https://unstable-service/api/data')
);
breaker.fire()
.then(response => console.log(response.data))
.catch(err => console.error('Service unavailable'));
企业级 Axios 封装库示例
// enterprise-axios.js
import axios from 'axios';
import { getAuthToken, refreshToken } from './auth';
import { logApiEvent, logError } from './monitoring';
import CircuitBreaker from './circuit-breaker';
const createApiClient = (baseConfig = {}) => {
const client = axios.create({
baseURL: process.env.API_BASE_URL,
timeout: 15000,
...baseConfig
});
// 请求拦截器 - 认证
client.interceptors.request.use(config => {
const token = getAuthToken();
if (token) {
config.headers.Authorization =Bearer ${token};
}
return config;
});
// 响应拦截器 - 令牌刷新
client.interceptors.response.use(
response => response,
async error => {
const originalRequest = error.config;
if (error.response?.status === 401 && !originalRequest._retry) {
originalRequest._retry = true;
try {
const newToken = await refreshToken();
originalRequest.headers.Authorization = `Bearer ${newToken}`;
return client(originalRequest);
} catch (refreshError) {
return Promise.reject(refreshError);
}
}
return Promise.reject(error);
}
);
// 封装请求方法
const wrapper = {
get: (url, config) => client.get(url, config),
post: (url, data, config) => client.post(url, data, config),
put: (url, data, config) => client.put(url, data, config),
delete: (url, config) => client.delete(url, config),
// 带断路器的安全请求
safeRequest: (method, url, data = null, config = {}) => {
const request = () => {
switch (method.toLowerCase()) {
case 'get': return client.get(url, { ...config, params: data });
case 'delete': return client.delete(url, config);
default: return client[method](url, data, config);
}
};
const breaker = new CircuitBreaker(request, {
name: `${method}:${url}`,
timeout: 30000
});
return breaker.fire();
},
// 带重试的请求
retryableRequest: (config, retries = 3, delay = 1000) => {
let retryCount = 0;
const execute = async () => {
try {
return await client(config);
} catch (error) {
if (retryCount < retries) {
retryCount++;
await new Promise(res => setTimeout(res, delay * retryCount));
return execute();
}
throw error;
}
};
return execute();
}
};
// 添加监控
client.interceptors.request.use(config => {
config.metadata = { startTime: Date.now() };
return config;
});
client.interceptors.response.use(
response => {
const duration
浙公网安备 33010602011771号