请求拦截器相关面试题

1. 请求拦截器和响应拦截器分别有什么作用?

请求拦截器管请求发出去之前的事,响应拦截器管请求回来之后的事。

继续追问:请求拦截器一般做什么?

最常见的就是统一加 Token、公共请求头和请求配置。 例如:

javascript 复制代码
axios.interceptors.request.use(config => {
  const token = getToken();

  if (token) {
    config.headers.Authorization = `Bearer ${token}`;
  }

  return config;
});

继续追问:响应拦截器一般做什么?

主要是统一处理响应数据和错误。 比如:

javascript 复制代码
axios.interceptors.response.use(
  response => {
    return response.data;
  },
  error => {
    if (error.response?.status === 401) {
      // Token 失效
    }

    return Promise.reject(error);
  }
);

2. 为什么要封装一层请求,而不是每个地方直接用 Axios?

就是把重复的请求逻辑统一掉,让业务代码只管调接口。

比如业务代码只需要:

javascript 复制代码
const user = await getUser();

而不用每个地方都写:

text 复制代码
加 Token
设置 Header
处理 401
处理错误
设置超时

3. Token 过期了怎么办?

收到 401 后刷新 Token,刷新成功再把原请求重新发一次。

流程:

text 复制代码
请求
 ↓
401
 ↓
刷新 Token
 ↓
成功
 ↓
重新请求原接口

4. 如果同时有很多请求都返回 401 呢?

不能让每个请求都去刷新 Token,只能同时刷新一次,其他请求等它。

例如:

text 复制代码
请求 A ──→ 401 ──┐
请求 B ──→ 401 ──┤
请求 C ──→ 401 ──┤
                  ↓
              刷新 Token
                  ↓
                成功
             ↙    ↓    ↘
           A重试  B重试  C重试

常见做法是共享一个 Promise:

javascript 复制代码
let refreshPromise = null;

async function refreshTokenOnce() {
  if (!refreshPromise) {
    refreshPromise = refreshToken()
      .finally(() => {
        refreshPromise = null;
      });
  }

  return refreshPromise;
}

核心就是:

同一时间只能有一个刷新请求。


5. Token 刷新失败怎么办?

刷新失败就不能继续重试了,一般清掉登录状态,让用户重新登录。

否则就会出现:

text 复制代码
401
 ↓
刷新失败
 ↓
重新请求
 ↓
401
 ↓
继续刷新
 ↓
......

所以必须有明确的失败出口。


6. 所有请求失败都应该自动重试吗?

不应该,要看失败原因和请求本身能不能安全重试。

例如:

text 复制代码
GET 查询
→ 一般可以考虑重试

POST 创建订单
→ 不能随便重试

支付请求
→ 更不能简单自动重试

因为有些请求重复执行会产生实际业务影响。


7. 怎么做请求重试?

一般会限制重试次数,而且只对明确可以重试的错误重试。

例如:

javascript 复制代码
async function requestWithRetry(request, maxRetry = 3) {
  let count = 0;

  while (true) {
    try {
      return await request();
    } catch (error) {
      count++;

      if (count > maxRetry || !canRetry(error)) {
        throw error;
      }

      await sleep(1000 * count);
    }
  }
}

这里还可以继续追问:

为什么不能无限重试?

因为网络异常可能一直存在,无限重试会把问题放大。


8. 请求去重是怎么做的?

核心就是给请求生成一个唯一 Key,相同请求正在执行时就不要重复发。

例如:

text 复制代码
method + url + params + body
             ↓
         requestKey

第一次:

text 复制代码
GET /user → 发请求

第二次:

text 复制代码
GET /user → 发现相同请求正在执行
        → 复用 / 取消

具体选择哪种,要看业务需求。


9. 怎么取消请求?

现在一般直接用 AbortController。

javascript 复制代码
const controller = new AbortController();

fetch('/api/user', {
  signal: controller.signal
});

// 取消
controller.abort();

典型场景就是搜索:

text 复制代码
输入 A
 ↓
请求 A

输入 AB
 ↓
取消 A
 ↓
请求 AB

输入 ABC
 ↓
取消 AB
 ↓
请求 ABC

避免旧请求回来以后把新数据覆盖掉。


10. 所有错误都在响应拦截器里弹 Toast,可以吗?

不建议,请求层负责识别和处理错误,具体怎么提示最好由业务决定。

因为不同接口的错误处理可能不一样:

text 复制代码
有的 → Toast
有的 → 页面展示
有的 → 静默处理
有的 → 自己处理

如果请求层直接绑定 UI,就容易变成:

text 复制代码
请求层
  ↓
Axios
  ↓
Toast
  ↓
具体 UI 框架

耦合会比较重。


11. 请求拦截器是不是只能 Axios 有?

不是,拦截请求是一个设计思路,不是 Axios 独有的功能。

Axios 自己提供了拦截器;如果用 fetch,也可以自己封装:

javascript 复制代码
async function request(url, options) {
  const config = beforeRequest(url, options);

  const response = await fetch(
    config.url,
    config.options
  );

  return afterResponse(response);
}

一道题怎么连续追?

面试官:

请求拦截器和响应拦截器有什么作用?

你先答:请求拦截器管请求发出去之前的事,响应拦截器管请求回来之后的事。

面试官继续:

Token 怎么处理?

请求拦截器统一加 Token。

Token 过期呢?

收到 401 就刷新 Token,成功后重发原请求。

如果同时 10 个请求都 401 呢?

不能让 10 个请求一起刷新,只能刷新一次,其他请求等刷新结果。

刷新失败呢?

清掉登录状态,让用户重新登录,不能继续重试。

那请求重试呢?

只重试明确可以安全重试的请求,而且要限制次数。

你还会考虑什么?

请求取消、请求去重、错误统一处理,这些都可以根据业务需要加。

这就比单纯回答"请求拦截器加 Token,响应拦截器处理错误"明显高一个层次。

相关推荐
ShawnLiaoking1 小时前
ADS305 Big Data Lecuture4 Web Scraping
大数据·前端
liangshanbo12151 小时前
React面试题:Hooks 为什么不能在分支和循环里面写?
前端·javascript·react.js
她说彩礼65万1 小时前
C语言 const的使用
java·服务器·c语言
开开心心就好1 小时前
视频压缩工具推荐,绿色版免安装双击即用
java·前端·人工智能·spring·智能手机·intellij-idea·excel
Wang's Blog1 小时前
Java框架 SpringCloud 快速入门: Eureka 注册中心的搭建
java·spring cloud·eureka
西红柿炖牛腩3541 小时前
GLB 转 OBJ/PLY 后体积没变?3D 模型不减面变小靠什么
前端·javascript·3d
欣欣之王来了1 小时前
前端开发学习路线图:2026年Vue方向最新版
前端·学习·架构·项目·vue3教程
专业程序开发源1 小时前
springboot古城景区管理系统88564-计算机课程设计、毕业设计
java·vue.js·spring boot·后端·spring·php·课程设计
夏幻灵1 小时前
前端八股:Vue2 与 Vue3 的核心区别:响应式、Composition API 与性能优化
前端