axios 的拦截器、适配器和取消请求是怎样工作的?

先理解原理和示例,再练习完整口述与追问。

配置按默认值、实例、单次调用合并;请求拦截器后注册先执行,响应拦截器按注册顺序执行,中间是真正发请求的 dispatchRequest;use 返回 id,用 eject(id) 注销。适配器在浏览器用 XHR(新版也可选 fetch),在 Node 用 http 模块。取消用 AbortController 的 signal,旧的 CancelToken 已废弃。

axios 把一次请求组织成 Promise 链:请求拦截器(按注册的逆序)→ 转换请求数据 → 适配器发送 → 转换响应数据 → 响应拦截器(按注册顺序)。任一环节返回拒绝的 Promise,后续成功回调就被跳过,进入下一个错误处理。validateStatus 默认只把 2xx 视为成功。

适配器把统一的配置翻译为具体环境的请求:浏览器端检测 XMLHttpRequest 是否可用,Node 端检测 process 与 http 模块,axios 1.7 起还提供 fetch 适配器,可通过 adapter 配置选择。withCredentials: true 让跨域 XHR 携带 Cookie,前提是服务端返回具体的 Access-Control-Allow-Origin 和 Access-Control-Allow-Credentials: true。

axios 默认把对象序列化为 JSON 并设置 Content-Type: application/json。后端只解析表单时就会收不到数据,可传 URLSearchParams 或 FormData,并统一前后端约定。

js
const http = axios.create({ baseURL: '/api', timeout: 10000 })
const authId = http.interceptors.request.use(config => {
  config.headers.Authorization = `Bearer ${getToken()}`
  return config
})
http.interceptors.response.use(
  response => response.data,
  error => Promise.reject(normalizeError(error))
)
const controller = new AbortController()
http.get('/orders', { signal: controller.signal })
controller.abort()
http.interceptors.request.eject(authId)

批量请求同时失败时,在响应拦截器中只记录错误,由一个“提示队列”去重后弹出一次 toast,而不是每个请求各弹一次。

拦截器里忘记 return config 或 return response 会让后续拿到 undefined;在响应拦截器中吞掉错误并返回成功值,会让调用方误以为请求成功。

axios 先合并默认、实例和本次配置,再把请求拦截器、实际发送和响应拦截器串成 Promise 链,请求拦截器后加的先执行,响应拦截器按顺序执行,注册返回的 id 可以 eject 掉。真正发送交给适配器,浏览器用 XHR 或 fetch,Node 用 http 模块。取消用 AbortController 的 signal。另外 axios 默认发 JSON,后端只收表单时要改成 URLSearchParams 或统一约定。