Axios 高级特性概览
Axios 不仅支持基本的 HTTP 请求,还提供了许多高级特性,包括文件上传下载、进度监控、CSRF 防护、请求转换等。
1. 文件上传
基础文件上传
javascript// HTML // <input type="file" id="fileInput" /> const uploadFile = async (file) => { const formData = new FormData(); formData.append('file', file); try { const response = await axios.post('/api/upload', formData, { headers: { 'Content-Type': 'multipart/form-data' } }); return response.data; } catch (error) { console.error('上传失败:', error); throw error; } }; // 使用 const fileInput = document.getElementById('fileInput'); fileInput.addEventListener('change', (e) => { const file = e.target.files[0]; uploadFile(file); });
多文件上传
javascriptconst uploadMultipleFiles = async (files) => { const formData = new FormData(); files.forEach((file, index) => { formData.append(`file${index}`, file); }); // 或者使用相同字段名 // files.forEach(file => { // formData.append('files', file); // }); const response = await axios.post('/api/upload-multiple', formData, { headers: { 'Content-Type': 'multipart/form-data' } }); return response.data; };
带进度条的文件上传
javascriptconst uploadWithProgress = (file, onProgress) => { const formData = new FormData(); formData.append('file', file); return axios.post('/api/upload', formData, { headers: { 'Content-Type': 'multipart/form-data' }, onUploadProgress: (progressEvent) => { if (progressEvent.lengthComputable) { const percentCompleted = Math.round( (progressEvent.loaded * 100) / progressEvent.total ); onProgress(percentCompleted); } } }); }; // React 组件中使用 function FileUpload() { const [progress, setProgress] = useState(0); const handleUpload = async (file) => { try { const result = await uploadWithProgress(file, setProgress); console.log('上传成功:', result); } catch (error) { console.error('上传失败:', error); } }; return ( <div> <input type="file" onChange={(e) => handleUpload(e.target.files[0])} /> <progress value={progress} max="100" /> <span>{progress}%</span> </div> ); }
2. 文件下载
基础文件下载
javascriptconst downloadFile = async (url, filename) => { try { const response = await axios.get(url, { responseType: 'blob' // 重要:设置响应类型为 blob }); // 创建下载链接 const blob = new Blob([response.data]); const downloadUrl = window.URL.createObjectURL(blob); const link = document.createElement('a'); link.href = downloadUrl; link.download = filename; document.body.appendChild(link); link.click(); document.body.removeChild(link); window.URL.revokeObjectURL(downloadUrl); } catch (error) { console.error('下载失败:', error); } }; // 使用 downloadFile('/api/download/report.pdf', 'report.pdf');
带进度条的文件下载
javascriptconst downloadWithProgress = async (url, filename, onProgress) => { const response = await axios.get(url, { responseType: 'blob', onDownloadProgress: (progressEvent) => { if (progressEvent.lengthComputable) { const percentCompleted = Math.round( (progressEvent.loaded * 100) / progressEvent.total ); onProgress(percentCompleted); } } }); const blob = new Blob([response.data]); const downloadUrl = window.URL.createObjectURL(blob); const link = document.createElement('a'); link.href = downloadUrl; link.download = filename; document.body.appendChild(link); link.click(); document.body.removeChild(link); window.URL.revokeObjectURL(downloadUrl); };
3. CSRF 防护
自动 CSRF Token 处理
javascriptconst instance = axios.create({ // 从 cookie 中读取 CSRF token 的字段名 xsrfCookieName: 'XSRF-TOKEN', // 请求头中发送 CSRF token 的字段名 xsrfHeaderName: 'X-XSRF-TOKEN', // 允许携带 cookie withCredentials: true });
手动设置 CSRF Token
javascript// 从 meta 标签获取 CSRF token const csrfToken = document.querySelector('meta[name="csrf-token"]').getAttribute('content'); const instance = axios.create({ headers: { 'X-CSRF-TOKEN': csrfToken } }); // 或者通过拦截器动态设置 instance.interceptors.request.use(config => { const token = document.querySelector('meta[name="csrf-token"]')?.getAttribute('content'); if (token) { config.headers['X-CSRF-TOKEN'] = token; } return config; });
4. 请求和响应转换
请求数据转换
javascriptconst instance = axios.create({ // 在请求发送到服务器之前修改请求数据 transformRequest: [ function (data, headers) { // 对 data 进行转换 if (data instanceof FormData) { return data; } // 添加时间戳防止缓存 if (data && typeof data === 'object') { data._timestamp = Date.now(); } return JSON.stringify(data); } ] });
响应数据转换
javascriptconst instance = axios.create({ // 在传递给 then/catch 之前修改响应数据 transformResponse: [ function (data) { // 解析 JSON const parsed = JSON.parse(data); // 统一处理响应格式 if (parsed.code !== 0) { throw new Error(parsed.message); } return parsed.data; } ] });
5. 参数序列化
自定义参数序列化
javascriptimport qs from 'qs'; const instance = axios.create({ // 自定义 params 序列化 paramsSerializer: { encode?: (param: string): string => encodeURIComponent(param), // 自定义编码函数 serialize?: (params: Record<string, any>, options?: ParamsSerializerOptions): string => { // 使用 qs 库进行序列化 return qs.stringify(params, { arrayFormat: 'brackets' }); }, indexes: false // 数组参数不使用索引 } }); // 使用 instance.get('/api/search', { params: { q: 'keyword', tags: ['javascript', 'axios'] } }); // 结果: /api/search?q=keyword&tags[]=javascript&tags[]=axios
6. 代理配置
javascript// Node.js 环境 const instance = axios.create({ proxy: { protocol: 'https', host: '127.0.0.1', port: 9000, auth: { username: 'mikeymike', password: 'rapunz3l' } } }); // 或者使用环境变量 const instance = axios.create({ proxy: false // 禁用代理 });
7. 适配器
自定义适配器
javascriptconst instance = axios.create({ adapter: (config) => { return new Promise((resolve, reject) => { // 自定义请求实现 const xhr = new XMLHttpRequest(); xhr.open(config.method.toUpperCase(), config.url); xhr.onload = () => { resolve({ data: xhr.response, status: xhr.status, statusText: xhr.statusText, headers: {}, config, request: xhr }); }; xhr.onerror = () => reject(new Error('Request failed')); xhr.send(config.data); }); } });
8. 验证状态码
javascriptconst instance = axios.create({ // 自定义合法状态码 validateStatus: (status) => { return status >= 200 && status < 300; // 默认值 // 或者接受所有状态码 // return true; // 或者只接受特定状态码 // return [200, 201, 204].includes(status); } });
9. 最大内容长度和重定向
javascriptconst instance = axios.create({ // 最大响应内容长度(字节) maxContentLength: 2000, // 最大请求内容长度(字节) maxBodyLength: 2000, // 最大重定向次数 maxRedirects: 5, // 在 Node.js 中遵循重定向 // 在浏览器中此配置无效(浏览器自动处理重定向) });
10. 完整的高级配置示例
javascriptimport axios from 'axios'; import qs from 'qs'; const advancedApi = axios.create({ baseURL: 'https://api.example.com', timeout: 30000, // 请求头 headers: { 'Accept': 'application/json', 'Content-Type': 'application/json' }, // 携带 cookie withCredentials: true, // CSRF 防护 xsrfCookieName: 'XSRF-TOKEN', xsrfHeaderName: 'X-XSRF-TOKEN', // 响应类型 responseType: 'json', // 参数序列化 paramsSerializer: (params) => { return qs.stringify(params, { arrayFormat: 'repeat' }); }, // 请求转换 transformRequest: [ (data, headers) => { // 添加认证信息 const token = localStorage.getItem('token'); if (token) { headers.Authorization = `Bearer ${token}`; } // 如果不是 FormData,转换为 JSON if (data && !(data instanceof FormData)) { return JSON.stringify(data); } return data; } ], // 响应转换 transformResponse: [ (data) => { // 统一错误处理 if (data && data.code !== 0) { throw new Error(data.message); } return data?.data || data; } ], // 状态码验证 validateStatus: (status) => { return status >= 200 && status < 500; }, // 最大内容长度 maxContentLength: 50 * 1024 * 1024, // 50MB // 最大重定向次数 maxRedirects: 5 }); // 添加进度监控拦截器 advancedApi.interceptors.request.use(config => { if (config.onUploadProgress || config.onDownloadProgress) { console.log('请求包含进度监控'); } return config; }); export default advancedApi;
最佳实践
- 文件上传:始终使用 FormData,设置正确的 Content-Type
- 文件下载:设置 responseType 为 'blob' 或 'arraybuffer'
- CSRF 防护:正确配置 xsrfCookieName 和 xsrfHeaderName
- 进度监控:在需要用户体验的场景中使用
- 数据转换:统一处理请求和响应数据格式
- 错误处理:在 transformResponse 中统一处理业务错误