axios 实例如何创建和配置?axios.create() 的使用方法与核心原理
axios.create() 是 axios 提供的工厂方法,用于创建一个拥有独立配置的 axios 实例。与直接使用全局 axios 对象不同,实例之间互不影响,适合在项目中对接多个服务或需要不同默认配置的场景。
核心答案
axios.create() 接收一个配置对象,返回一个新的 axios 实例,该实例拥有与全局 axios 相同的请求方法,但配置彼此隔离:
javascriptconst instance = axios.create({ baseURL: 'https://api.example.com', timeout: 10000, headers: { 'X-Custom-Header': 'foobar' } }); instance.get('/users'); // 实际请求 https://api.example.com/users
面试关键点: axios.create() 创建的实例与全局 axios 共享原型方法,但拥有独立的 defaults、interceptors,互不干扰。源码中 create 调用了 createInstance,通过 bind 绑定新上下文并拷贝拦截器链。
追问:axios.create() 和直接修改 axios.defaults 有什么区别?
修改 axios.defaults 影响全局所有请求,而 axios.create() 创建的实例配置独立,适合多服务、多环境场景。实际项目中推荐使用实例而非修改全局默认值。
配置选项分类
基础配置
最常用的配置项集中在请求地址、超时和请求头:
javascriptconst instance = axios.create({ baseURL: 'https://api.example.com/v1', // 请求 URL 前缀 timeout: 10000, // 超时时间(毫秒) headers: { // 自定义请求头 'Content-Type': 'application/json', 'Accept': 'application/json' }, method: 'get', // 默认请求方法 params: { page: 1 }, // URL 查询参数 data: { name: 'test' } // 请求体数据 });
进阶配置
实际项目中常涉及跨域凭证、响应类型和安全相关配置:
javascriptconst instance = axios.create({ withCredentials: true, // 跨域请求携带 cookie responseType: 'json', // 响应数据类型:json/blob/stream 等 responseEncoding: 'utf8', // 响应编码 xsrfCookieName: 'XSRF-TOKEN', // XSRF 防护 cookie 名 xsrfHeaderName: 'X-XSRF-TOKEN', // XSRF 防护 header 名 maxRedirects: 5, // 最大重定向次数 maxContentLength: 2000, // 响应体最大长度 onUploadProgress: (e) => {}, // 上传进度回调 onDownloadProgress: (e) => {} // 下载进度回调 });
配置优先级
这是面试高频考点。配置合并遵循四个层级,后者覆盖前者:
- 库默认值 — axios 内置的默认配置
axios.create()传入的配置 — 创建实例时指定- 实例的
defaults属性 — 创建后通过instance.defaults修改 - 请求时传入的配置 — 单次请求的 config 参数
javascript// 层级 1:库默认 timeout = 0 // 层级 2:创建时 timeout = 5000 const instance = axios.create({ timeout: 5000 }); // 层级 3:defaults 修改 timeout = 10000 instance.defaults.timeout = 10000; // 层级 4:请求时覆盖 timeout = 20000 ← 最终生效 instance.get('/data', { timeout: 20000 });
追问:headers 的合并策略和 timeout 一样吗?
不一样。timeout 等简单值直接覆盖,而 headers 采用深度合并策略——headers.common、headers[method] 会按层级递归合并,而非整体替换。理解这一点才能避免配置被意外覆盖。
实战场景
多后端服务
中大型项目通常对接多个微服务,各自拥有不同的 baseURL 和超时要求:
javascriptconst userService = axios.create({ baseURL: 'https://api.user-service.com', timeout: 5000 }); const orderService = axios.create({ baseURL: 'https://api.order-service.com', timeout: 10000 }); // 各实例独立使用,互不干扰 userService.get('/users/1'); orderService.get('/orders/123');
认证 API 与公开 API 分离
需要对不同接口设置不同的拦截逻辑时,实例隔离尤为重要:
javascript// 需要认证的实例 const authApi = axios.create({ baseURL: 'https://api.example.com', timeout: 10000 }); authApi.interceptors.request.use(config => { const token = localStorage.getItem('token'); if (token) config.headers.Authorization = `Bearer ${token}`; return config; }); // 公开接口实例——无需 token const publicApi = axios.create({ baseURL: 'https://api.example.com', timeout: 5000 });
完整封装方案
结合实例创建、拦截器和错误处理,形成项目级的请求封装:
javascriptimport axios from 'axios'; const api = axios.create({ baseURL: import.meta.env.VITE_API_URL || 'http://localhost:3000', timeout: 10000, headers: { 'Content-Type': 'application/json' } }); // 请求拦截:注入 token api.interceptors.request.use(config => { const token = localStorage.getItem('token'); if (token) config.headers.Authorization = `Bearer ${token}`; return config; }); // 响应拦截:统一错误处理 api.interceptors.response.use( response => response.data, error => { if (error.response?.status === 401) { localStorage.removeItem('token'); window.location.href = '/login'; } return Promise.reject(error); } ); export default api;
常见问题
实例能访问全局 axios 的拦截器吗? 不能。每个实例拥有独立的 interceptors 对象,创建实例时拦截器链从空开始,需要单独添加。
axios.create() 返回的是什么? 返回一个包装了 Axios 实例的函数,该函数绑定了当前上下文,同时挂载了 get、post 等快捷方法和 defaults、interceptors 属性。源码中通过 extend 将 Axios.prototype 上的方法拷贝到实例函数上。
实例方法有哪些? request、get、delete、head、options、post、put、patch、getUri,用法与全局 axios 一致。