Axios面试常见问题详解

axios面试常问题目及其详解

以下是前端面试中关于 Axios 的常见问题及详细解答,涵盖核心原理、实战场景和进阶优化,帮助你在面试中清晰展示技术深度。


1. Axios 是什么?它与原生 Fetch API 有何区别?

回答要点:
  • Axios 是什么:
    Axios 是一个基于 Promise 的 HTTP 客户端,用于浏览器和 Node.js 环境。它封装了底层的 XMLHttpRequest(浏览器)和 http 模块(Node.js),提供了更简洁的 API 和丰富的功能(如拦截器、自动转换 JSON 数据等)。
面试场景:

"在项目中为什么选择 Axios 而不是 Fetch?"

回答:

"Axios 的拦截器功能可以统一处理认证(如自动附加 Token)、错误提示(如 401 跳转登录页)和请求日志,减少重复代码。此外,Axios 自动转换 JSON 数据,避免了手动调用 response.json() 的繁琐操作,尤其在需要兼容 IE 时,Axios 的 Polyfill 支持更友好。"


2. Axios 的拦截器如何工作?实际项目中如何使用?

回答要点:
  • 拦截器类型:
    • 请求拦截器:在请求发送前执行(如附加 Token、修改请求头)。
    • 响应拦截器:在响应返回后执行(如统一处理错误、数据格式化)。
  • 代码示例:
javascript 复制代码
// 请求拦截器:附加 Token
axiosInstance.interceptors.request.use(config => {
  const token = localStorage.getItem('token');
  if (token) config.headers.Authorization = `Bearer ${token}`;
  return config;
});

// 响应拦截器:统一处理错误
axiosInstance.interceptors.response.use(
  response => response.data, // 直接返回数据部分
  error => {
    if (error.response?.status === 401) {
      // 跳转登录页
      window.location.href = '/login';
    }
    return Promise.reject(error);
  }
);
  • 实际场景:
    • 认证管理:自动附加 Token,避免每个请求手动添加。
    • 错误兜底:统一处理 4xx/5xx 错误,减少组件内的重复代码。
    • 数据格式化:后端返回数据包裹在 { code, data, message } 中,拦截器可提取 data 部分。
面试场景:

"如何通过拦截器实现用户登录状态的自动管理?"

回答:

"在请求拦截器中检查本地存储的 Token,并附加到请求头。在响应拦截器中,如果遇到 401 错误(Token 过期),自动清除本地 Token 并跳转登录页,无需在每个 API 调用中重复判断。"


3. 如何用 Axios 取消重复或过时的请求?

回答要点:
  • 取消方式:
    • CancelToken(旧版):
javascript 复制代码
const source = axios.CancelToken.source();
axios.get('/api/data', { cancelToken: source.token });
// 取消请求
source.cancel('用户取消操作');
复制代码
2.  AbortController(推荐):
javascript 复制代码
const controller = new AbortController();
axios.get('/api/data', { signal: controller.signal });
// 取消请求
controller.abort('请求超时');
  • 防重复提交:
    通过缓存请求标识(如 URL + 参数 + 时间戳),在拦截器中拦截短时间内重复的请求。
    示例:
javascript 复制代码
const pendingRequests = new Map();
axiosInstance.interceptors.request.use(config => {
  const requestKey = `${config.url}-${JSON.stringify(config.params)}`;
  if (pendingRequests.has(requestKey)) {
    pendingRequests.get(requestKey).abort(); // 取消前一个相同请求
  }
  const controller = new AbortController();
  config.signal = controller.signal;
  pendingRequests.set(requestKey, controller);
  return config;
});
axiosInstance.interceptors.response.use(response => {
  const requestKey = `${response.config.url}-${JSON.stringify(response.config.params)}`;
  pendingRequests.delete(requestKey); // 请求完成,移除缓存
  return response;
});
面试场景:

"用户快速点击按钮多次提交表单,如何避免重复请求?"

回答:

"在请求拦截器中生成请求的唯一标识(如 URL + 参数),并用 Map 缓存正在进行的请求。如果相同请求已存在,则调用 AbortController.abort() 取消前一个请求,确保只有最后一次请求被执行。"


4. Axios 如何处理跨域问题?CORS 和 JSONP 的区别?

回答要点:
  • Axios 跨域解决方案:

    • CORS(推荐):后端设置响应头(如 Access-Control-Allow-Origin),浏览器允许跨域请求。
      • 简单请求:直接发送请求。
      • 预检请求(Preflight):先发 OPTIONS 请求,后端需支持 OPTIONS 方法并返回允许的跨域头。
    • 代理服务器:开发时通过 Webpack DevServer 或 Nginx 反向代理,将请求转发到目标服务器(前端代码无跨域问题)。
  • CORS vs JSONP:

    |对比项|CORS|JSONP|

    |原理|基于 HTTP 头部的跨域控制|利用

面试场景:

"项目遇到跨域问题,如何通过 Axios 解决?"

回答:

"如果是开发环境,通过 Webpack DevServer 配置代理,将 API 请求转发到后端服务器。生产环境则让后端配置 CORS 头,允许前端域名访问。JSONP 仅作为备选方案,因仅支持 GET 且安全性较低。"


5. 如何实现 Axios 的请求重试机制?

回答要点:
  • 实现思路:
    在响应拦截器中捕获网络错误或特定状态码(如 5xx),通过递归或定时器重试请求。
    代码示例:
javascript 复制代码
axiosInstance.interceptors.response.use(null, error => {
  if (error.code === 'ECONNABORTED' || !error.response) {
    // 网络超时或断开,重试
    return retryRequest(error.config);
  }
  return Promise.reject(error);
});

function retryRequest(config, retryCount = 3) {
  if (retryCount <= 0) return Promise.reject('重试次数耗尽');
  config.__retryCount = config.__retryCount || 0;
  config.__retryCount += 1;
  return new Promise(resolve => {
    setTimeout(() => {
      resolve(axiosInstance(config));
    }, 1000 * config.__retryCount); // 指数退避
  }).then(response => response)
    .catch(err => retryRequest(config, retryCount - 1));
}
  • 适用场景:
    • 网络不稳定导致请求失败。
    • 后端服务临时不可用(如 502/504 错误)。
面试场景:

"如何优化弱网环境下的请求成功率?"

回答:

"通过拦截器实现请求重试机制,结合指数退避策略(如首次重试延迟 1s,第二次 2s),避免短时间内频繁重试加重服务器负担。同时限制最大重试次数(如 3 次),防止无限重试。"


6. Axios 的全局配置和实例化配置有何区别?

回答要点:
  • 全局默认配置:
    通过 axios.defaults 设置,影响所有请求(不推荐,易产生冲突)。
javascript 复制代码
axios.defaults.baseURL = 'https://api.example.com';
axios.defaults.timeout = 5000;
  • 实例化配置:
    创建独立的 Axios 实例,每个实例可单独配置,避免全局污染。
javascript 复制代码
const apiInstance = axios.create({
  baseURL: 'https://api.example.com',
  timeout: 5000,
});
apiInstance.interceptors.request.use(...); // 实例级拦截器
  • 优先级:
    实例配置 > 全局配置 > 请求配置(axios.get(url, { timeout: 10000 }) 可覆盖实例配置)。
面试场景:

"多个模块需要调用不同后端 API,如何管理 Axios 配置?"

回答:

"为每个模块创建独立的 Axios 实例,分别配置 baseURL 和拦截器。例如,用户模块实例指向 /user 接口,支付模块实例指向 /pay 接口,避免全局配置混乱。"


总结

在面试中回答 Axios 相关问题时,需结合 原理、实战场景 和 代码实现,突出以下能力:

  1. 底层机制的理解(如拦截器、取消请求)。
  2. 解决实际问题的经验(如跨域、重复提交、错误处理)。
  3. 代码设计的规范性(如实例化配置、重试机制)。
    通过清晰的逻辑和具体的例子,可以充分展示你对 Axios 的掌握程度和工程化思维。


下面是一些关于 Axios 在前端面试中常见的问题及其详解,涵盖了基础用法、配置、拦截器、错误处理等方面,适合前端开发岗位:


✅ 基本 Axios 面试题目详解

1. 什么是 Axios?它有哪些特点?

答案:

Axios 是一个基于 Promise 的 HTTP 客户端,用于浏览器和 Node.js。
特点:

  • 支持 Promise API
  • 支持请求/响应拦截器
  • 请求和响应数据转换
  • 自动转换 JSON 数据
  • 防止 CSRF/XSRF 攻击
  • 客户端支持取消请求(通过 CancelToken)
  • 支持并发请求(axios.all()

2. Axios 和 Fetch 的区别?

特点 Axios Fetch
默认数据格式 JSON 自动解析 需要手动解析 .json()
请求拦截器 支持 不支持
响应拦截器 支持 不支持
超时设置 支持 需手动实现
请求取消 支持 CancelToken 需使用 AbortController
浏览器兼容性 更好 较新浏览器支持更好

3. 如何配置全局默认值?

js 复制代码
axios.defaults.baseURL = 'https://api.example.com';
axios.defaults.timeout = 5000;
axios.defaults.headers.common['Authorization'] = 'Bearer token';

4. Axios 如何设置请求拦截器和响应拦截器?

js 复制代码
// 请求拦截器
axios.interceptors.request.use(config => {
  // 可添加 token 等操作
  config.headers['X-Custom-Header'] = 'value';
  return config;
}, error => Promise.reject(error));

// 响应拦截器
axios.interceptors.response.use(response => {
  return response.data; // 直接返回数据部分
}, error => {
  // 错误处理
  if (error.response) {
    // 服务端返回错误
    console.error('Error:', error.response.status);
  } else if (error.request) {
    // 没有响应
    console.error('No response received');
  } else {
    console.error('Request setup error:', error.message);
  }
  return Promise.reject(error);
});

5. Axios 如何发送 GET、POST 请求?

js 复制代码
// GET 请求
axios.get('/user', { params: { id: 1 } });

// POST 请求
axios.post('/user', { name: 'John', age: 25 });

6. 如何处理请求错误?

js 复制代码
axios.get('/user/123')
  .then(response => console.log(response))
  .catch(error => {
    if (error.response) {
      console.log('Status:', error.response.status);
      console.log('Data:', error.response.data);
    } else if (error.request) {
      console.log('No response:', error.request);
    } else {
      console.log('Error:', error.message);
    }
  });

7. 如何取消 Axios 请求?

js 复制代码
const CancelToken = axios.CancelToken;
const source = CancelToken.source();

axios.get('/user', {
  cancelToken: source.token
}).catch(thrown => {
  if (axios.isCancel(thrown)) {
    console.log('Request canceled', thrown.message);
  }
});

source.cancel('Request canceled by user');

8. 如何使用 Axios 并发请求?

js 复制代码
axios.all([
  axios.get('/user'),
  axios.get('/profile')
]).then(axios.spread((userRes, profileRes) => {
  console.log(userRes.data);
  console.log(profileRes.data);
}));

9. Axios 如何上传文件?

js 复制代码
const formData = new FormData();
formData.append('file', fileInput.files[0]);

axios.post('/upload', formData, {
  headers: { 'Content-Type': 'multipart/form-data' }
});

10. 如何在 Axios 中设置超时时间?

js 复制代码
axios.get('/slow-api', {
  timeout: 3000 // 毫秒
});

✅ 高阶 Axios 面试题目详解


1. Axios 请求流程底层是如何工作的?

回答要点:

Axios 封装了 XMLHttpRequest(浏览器端)或 http 模块(Node.js),主要流程如下:

  1. 创建 Axios 实例(配置合并)。
  2. 执行请求拦截器(通过拦截器链)。
  3. 发起请求(浏览器中通过 XMLHttpRequest)。
  4. 接收响应并执行响应拦截器。
  5. 返回 Promise。

底层通过一个责任链模式(InterceptorManager)来组织拦截器,实际调用栈如下:

js 复制代码
dispatchRequest(config) -> xhrAdapter(config) -> new XMLHttpRequest

2. Axios 拦截器是如何实现的?是同步还是异步?

回答要点:

  • 拦截器是通过拦截器链(interceptors)维护的:

    js 复制代码
    axios.interceptors.request.use(fn1);
    axios.interceptors.response.use(fn2);
  • 这些拦截器会被组成一个 Promise chain 链式结构:

js 复制代码
let chain = [dispatchRequest, undefined]; // 核心请求处理
// 前置拦截器从前往后插入
// 后置拦截器从后往前插入

// 然后通过 promise 链式调用处理请求
  • 所以拦截器是异步可控的 Promise 链调用机制

3. Axios 如何实现请求合并或去重(防止重复请求)?

回答要点:

可通过维护一个请求队列 Map 实现唯一 key:

js 复制代码
const pendingMap = new Map();

function generateKey(config) {
  const { url, method, params, data } = config;
  return `${method}&${url}&${JSON.stringify(params)}&${JSON.stringify(data)}`;
}

function addPending(config) {
  const key = generateKey(config);
  if (!pendingMap.has(key)) {
    config.cancelToken = new axios.CancelToken(cancel => {
      pendingMap.set(key, cancel);
    });
  } else {
    // 取消已有重复请求
    pendingMap.get(key)();
  }
}

4. 如何封装 Axios 支持自动刷新 token(如 401 自动重发)?

回答要点:

  1. 在响应拦截器中捕获 401。
  2. 发起 refreshToken 请求(需要排队等待)。
  3. 更新 token 后重放之前失败的请求。

关键代码片段:

js 复制代码
let isRefreshing = false;
let failedQueue = [];

axios.interceptors.response.use(
  res => res,
  async error => {
    const originalRequest = error.config;
    if (error.response.status === 401 && !originalRequest._retry) {
      if (!isRefreshing) {
        isRefreshing = true;
        const newToken = await refreshToken();
        axios.defaults.headers.common['Authorization'] = `Bearer ${newToken}`;
        failedQueue.forEach(cb => cb(newToken));
        failedQueue = [];
        isRefreshing = false;
      }

      return new Promise(resolve => {
        failedQueue.push(token => {
          originalRequest.headers['Authorization'] = 'Bearer ' + token;
          resolve(axios(originalRequest));
        });
      });
    }

    return Promise.reject(error);
  }
);

5. Axios 在 Node.js 和浏览器中有何差异?

特性 浏览器端 Node.js
请求模块 XMLHttpRequest http / https
Cookie 自动携带 需手动配置
XSRF 有默认支持 需自己配置
适配器 xhrAdapter httpAdapter

Axios 使用的是 adapter 模式:defaultAdapter 会根据运行环境自动选择。


6. 如何在 Axios 中实现重试机制?

回答要点:

可以通过封装请求逻辑或使用拦截器实现简单重试逻辑:

js 复制代码
axios.interceptors.response.use(null, async error => {
  const config = error.config;
  if (!config || config.__retryCount >= 3) return Promise.reject(error);

  config.__retryCount = config.__retryCount || 0;
  config.__retryCount += 1;

  // 延迟重试
  await new Promise(res => setTimeout(res, 1000));
  return axios(config);
});

7. Axios 源码中的 InterceptorManager 是怎么工作的?

回答要点:

它维护了一个拦截器队列(handlers 数组),每个元素都有:

js 复制代码
{
  fulfilled: Function,
  rejected: Function
}

当执行请求时,会将所有拦截器依次插入 Promise 链中:

js 复制代码
let chain = [...requestInterceptors, dispatchRequest, ...responseInterceptors];

通过 Promise.resolve(config).then(...) 顺序执行所有拦截器。


8. Axios 如何实现适配器 Adapter 机制?

回答要点:

js 复制代码
const adapter = config.adapter || defaultAdapter;
return adapter(config).then(...)

Axios 默认支持两种 adapter:

  • xhrAdapter:浏览器端用 XMLHttpRequest
  • httpAdapter:Node.js 用 http.request

适配器允许我们定制不同平台下的请求方式,非常灵活。


9. Axios 如何防止 CSRF 攻击?

回答要点:

Axios 支持自动携带 CSRF Token:

js 复制代码
axios.defaults.xsrfCookieName = 'XSRF-TOKEN';
axios.defaults.xsrfHeaderName = 'X-XSRF-TOKEN';

如果服务端通过 Cookie 设置了 XSRF-TOKEN,Axios 会自动读取并在请求头加上 X-XSRF-TOKEN


10. Axios 是如何合并配置项的?为什么有些配置全局无法覆盖?

回答要点:

Axios 使用 utils.mergeConfig() 深度合并默认配置和实例配置,其中:

  • 一些字段采用深合并(如 headers
  • 一些字段直接覆盖(如 url, timeout

源码中的合并策略控制了不同字段的合并行为,导致有时 axios.defaults 无法覆盖实例设置。


相关推荐
程序员阿超的博客8 分钟前
React动态渲染:如何用map循环渲染一个列表(List)
前端·react.js·前端框架
magic 24510 分钟前
模拟 AJAX 提交 form 表单及请求头设置详解
前端·javascript·ajax
小小小小宇5 小时前
前端 Service Worker
前端
只喜欢赚钱的棉花没有糖5 小时前
http的缓存问题
前端·javascript·http
小小小小宇6 小时前
请求竞态问题统一封装
前端
loriloy6 小时前
前端资源帖
前端
源码超级联盟6 小时前
display的block和inline-block有什么区别
前端
GISer_Jing6 小时前
前端构建工具(Webpack\Vite\esbuild\Rspack)拆包能力深度解析
前端·webpack·node.js
让梦想疯狂6 小时前
开源、免费、美观的 Vue 后台管理系统模板
前端·javascript·vue.js
海云前端6 小时前
前端写简历有个很大的误区,就是夸张自己做过的东西。
前端