Axios POST 请求的 Transform 处理
Axios 本身已经内置了请求和响应拦截器(interceptors)机制,可以方便地实现 transform 处理。下面我将详细介绍如何使用 Axios 进行 POST 请求的 transform 处理。
基础封装
import axios from 'axios';
class ApiClient {
constructor(baseURL = '') {
this.instance = axios.create({
baseURL,
timeout: 10000,
headers: {
'Content-Type': 'application/json',
},
});
// 添加请求拦截器
this.instance.interceptors.request.use(
this.transformRequest,
this.transformRequestError
);
// 添加响应拦截器
this.instance.interceptors.response.use(
this.transformResponse,
this.transformResponseError
);
}
/**
* 请求transform
* @param {Object} config - axios 请求配置
* @returns {Object} 转换后的请求配置
*/
transformRequest(config) {
// 可以在这里添加认证token等
// config.headers.Authorization = `Bearer ${localStorage.getItem('token')}`;
// 对POST请求数据进行处理
if (config.method?.toLowerCase() === 'post' && config.data) {
// 示例:添加请求时间戳
config.data = {
...config.data,
_timestamp: Date.now(),
};
// 可以在这里对数据进行加密等操作
// config.data = this.encryptData(config.data);
}
return config;
}
/**
* 请求错误transform
* @param {Error} error
* @returns {Promise} 转换后的错误
*/
transformRequestError(error) {
return Promise.reject(error);
}
/**
* 响应transform
* @param {Object} response - axios 响应对象
* @returns {Object} 转换后的响应数据
*/
transformResponse(response) {
// 可以在这里对响应数据进行统一处理
// 例如解密数据、标准化响应格式等
// 示例:直接返回data字段
return response.data;
}
/**
* 响应错误transform
* @param {Error} error
* @returns {Promise} 转换后的错误
*/
transformResponseError(error) {
if (error.response) {
// 服务器返回了错误状态码 (4xx, 5xx)
const { status, data } = error.response;
error.message = data?.message || `请求失败,状态码: ${status}`;
error.status = status;
error.data = data;
} else if (error.request) {
// 请求已发出但没有收到响应
error.message = '网络错误,请检查网络连接';
} else {
// 请求配置出错
error.message = '请求配置错误';
}
return Promise.reject(error);
}
/**
* POST 请求
* @param {string} url - 请求路径
* @param {Object} data - 请求数据
* @param {Object} config - axios 配置
* @returns {Promise} 请求结果
*/
post(url, data = {}, config = {}) {
return this.instance.post(url, data, config);
}
// 可以添加其他HTTP方法...
}
使用示例
const api = new ApiClient('https://api.example.com');
// 基本使用
api.post('/users', { name: 'John', age: 30 })
.then(data => console.log('成功:', data))
.catch(error => console.error('失败:', error.message));
// 带额外配置
api.post('/login', { username: 'admin', password: '123456' }, {
headers: {
'X-Custom-Header': 'value'
},
timeout: 5000
});
高级 Transform 功能
1. 请求数据加密/解密
transformRequest(config) {
// 加密请求数据
if (config.method?.toLowerCase() === 'post' && config.data) {
config.data = this.encrypt(config.data);
}
return config;
}
transformResponse(response) {
// 解密响应数据
if (response.data && typeof response.data === 'object') {
response.data = this.decrypt(response.data);
}
return response.data;
}
encrypt(data) {
// 实际项目中应使用更安全的加密方式
return {
payload: btoa(JSON.stringify(data)),
version: '1.0'
};
}
decrypt(data) {
try {
if (data.payload) {
return JSON.parse(atob(data.payload));
}
return data;
} catch (e) {
console.error('解密失败', e);
return data;
}
}
2. 自动重试机制
constructor(baseURL = '') {
// ...其他初始化代码
this.retryCount = 3;
this.retryDelay = 1000;
}
transformResponseError(error) {
const config = error.config;
// 如果没有重试配置或者已经达到最大重试次数
if (!config || !config.__retryCount || config.__retryCount >= this.retryCount) {
return Promise.reject(this.normalizeError(error));
}
config.__retryCount = config.__retryCount || 0;
config.__retryCount += 1;
// 创建新的Promise来实现延迟重试
const delay = new Promise(resolve => {
setTimeout(() => resolve(), this.retryDelay * config.__retryCount);
});
return delay.then(() => this.instance(config));
}
normalizeError(error) {
// ...之前的错误处理逻辑
}
3. 请求取消功能
constructor(baseURL = '') {
// ...其他初始化代码
this.cancelTokenSource = axios.CancelToken.source();
}
post(url, data = {}, config = {}) {
// 将取消令牌加入配置
const newConfig = {
...config,
cancelToken: this.cancelTokenSource.token
};
return this.instance.post(url, data, newConfig);
}
cancelRequest(message = '请求已取消') {
this.cancelTokenSource.cancel(message);
// 创建新的取消令牌,以便后续请求
this.cancelTokenSource = axios.CancelToken.source();
}
// 使用示例
const api = new ApiClient('https://api.example.com');
const request = api.post('/data', { query: 'test' });
// 需要时取消请求
api.cancelRequest();
TypeScript 版本
import axios, { AxiosInstance, AxiosRequestConfig, AxiosResponse, AxiosError } from 'axios';
interface ApiResponse<T = any> {
code: number;
message: string;
data: T;
}
interface ApiError extends Error {
status?: number;
data?: any;
config?: AxiosRequestConfig;
}
class ApiClient {
private instance: AxiosInstance;
private cancelTokenSource = axios.CancelToken.source();
constructor(baseURL: string = '') {
this.instance = axios.create({
baseURL,
timeout: 10000,
headers: {
'Content-Type': 'application/json',
},
});
this.setupInterceptors();
}
private setupInterceptors() {
// 请求拦截器
this.instance.interceptors.request.use(
(config: AxiosRequestConfig) => this.transformRequest(config),
(error: AxiosError) => this.transformRequestError(error)
);
// 响应拦截器
this.instance.interceptors.response.use(
(response: AxiosResponse) => this.transformResponse(response),
(error: AxiosError) => this.transformResponseError(error)
);
}
private transformRequest(config: AxiosRequestConfig): AxiosRequestConfig {
// 添加认证token
// const token = localStorage.getItem('token');
// if (token) {
// config.headers = {
// ...config.headers,
// Authorization: `Bearer ${token}`,
// };
// }
// POST请求数据处理
if (config.method?.toLowerCase() === 'post' && config.data) {
config.data = {
...config.data,
_timestamp: Date.now(),
};
}
return config;
}
private transformRequestError(error: AxiosError): Promise<AxiosError> {
return Promise.reject(error);
}
private transformResponse(response: AxiosResponse): any {
// 直接返回data字段
return response.data;
}
private transformResponseError(error: AxiosError): Promise<ApiError> {
const normalizedError: ApiError = new Error();
if (error.response) {
// 服务器返回了错误状态码
const { status, data } = error.response;
normalizedError.message = (data as any)?.message || `请求失败,状态码: ${status}`;
normalizedError.status = status;
normalizedError.data = data;
} else if (error.request) {
// 请求已发出但没有收到响应
normalizedError.message = '网络错误,请检查网络连接';
} else {
// 请求配置出错
normalizedError.message = error.message || '请求配置错误';
}
return Promise.reject(normalizedError);
}
public post<T = any>(url: string, data: any = {}, config: AxiosRequestConfig = {}): Promise<T> {
const newConfig = {
...config,
cancelToken: this.cancelTokenSource.token,
};
return this.instance.post(url, data, newConfig);
}
public cancelRequest(message: string = '请求已取消'): void {
this.cancelTokenSource.cancel(message);
this.cancelTokenSource = axios.CancelToken.source();
}
}
// 使用示例
interface User {
id: number;
name: string;
age: number;
}
const api = new ApiClient('https://api.example.com');
api.post<User>('/users', { name: 'John', age: 30 })
.then((user: User) => console.log('创建的用户:', user))
.catch((error: ApiError) => console.error('错误:', error.message));
与原生 Fetch 封装的对比
- 内置拦截器机制:Axios 原生支持请求/响应拦截器,transform 处理更简单
- 自动JSON转换:Axios 自动处理请求/响应的JSON转换
- 更完善的错误处理:Axios 区分了网络错误、超时错误和HTTP状态码错误
- 取消请求:Axios 内置了取消请求的机制
- 浏览器/Node.js兼容:Axios 在两种环境下都能工作
- 进度跟踪:Axios 支持上传/下载进度跟踪
这个 Axios 封装提供了完整的 transform 处理点,你可以根据项目需求在请求前、响应后和错误时进行各种数据转换和处理。