Axios 面试题 (2023-09-15更新)

有封装过 axios 么?封装一个 axios?

import axios from 'axios'

// 创建axios实例
const service = axios.create({
  baseURL: '',
  timeout: '',
  headers: {}
})

// 配置请求拦截器
// 接收两个参数
service.interceptors.request.use(
  (confit) => {
    // 在发送请求之前,需要做什么处理,可以在这里加
    return config
  },
  (err) => {
    // 对错误做些什么
    return Promise.reject(err)
  }
)

// 添加响应拦截器
// 接收两个参数
axios.interceptors.response.use(
  (res) => {
    // 2xx 范围内的状态码都会触发该函数。
    // 对响应数据做点什么
    return res
  },
  (err) => {
    // 超出 2xx 范围的状态码都会触发该函数。
    // 对响应错误做点什么
    return Promise.reject(err)
  }
)

怎么取消一个请求?

axios 提供 CancelToken.source 用于取消请求

const CancelToken = axios.CancelToken
const source = CancelToken.source()

const params = { name: '' }
const config = { cancelToken: source.token }
axios.post('api/test', params, config).catch(function (thrown) {
  if (axios.isCancel(thrown)) {
    // 请求被取消后的处理
  } else {
    // 处理错误
  }
})

// 取消请求
source.cancel()

谈谈你对 axios 的理解?

axios 是基于 XMLHttpRequest 服务来执行 HTTP 请求,支持 Promise
可以拦截请求和响应
可以转换请求数据和响应数据,对相应的内容进行自动转换

为什么 axios 支持浏览器发送请求,也支持 node 发送请求?

使用的是适配器模式,判断环境,根据环境使用对应的适配器

  1. 在 default.js 文件中判断环境,然后根据环境使用对应的适配器
  2. 在 axios.defaults.adapter 中可以找到

axios 有哪些常用方法?

  • axios.get(url[, config])
  • axios.delete(url[, config])
  • axios.post(url[, data[, config]])
  • axios.put(url[, data[, config]])

说一下 axios 的相关配置属性?

  • url 请求的服务器 url
  • baseURL 将自动加载 url 前面,除非 url 是个绝对地址
  • headers 自定义请求头
  • params 是与请求一起发送的 URL 参数,必须是一个简单对象或 URLSearchParams 对象
  • transformRequest 允许在向服务器发送前,修改请求数据,只能用在 put、post、patch 这几个请求方法
  • responseType 表示浏览器将要响应的数据类型,默认 json,还有其他类型:arraybuffer、document、json、text、stream

axios 拦截器的原理?

Axios.prototype.request 是真正的请求
在 Axios.prototype.request 维护一个数组
将 request 请求拦截器放到数组的前面,将 response 响应拦截器放到数组的后面,
组成 Promise 链式调用

function Axios() {
  this.interceptors = {
    //两个拦截器
    request: new interceptorsManner(),
    response: new interceptorsManner()
  }
}

//真正的请求
Axios.prototype.request = function () {
  let chain = [dispatchRequest, undefined] //这儿的undefined是为了补位,因为拦截器的返回有两个
  let promise = Promise.resolve()
  //将两个拦截器中的回调加入到chain数组中
  this.interceptors.request.handler.forEach((interceptor) => {
    chain.unshift(interceptor.fulfilled, interceptor.rejected)
  })
  this.interceptors.response.handler.forEach((interceptor) => {
    chain.push(interceptor.fulfilled, interceptor.rejected)
  })
  while (chain.length) {
    //promise.then的链式调用,下一个then中的chain为上一个中的返回值,每次会减去两个
    //这样就实现了在请求的时候,先去调用请求拦截器的内容,再去请求接口,返回之后再去执行响应拦截器的内容
    promise = promise.then(chain.shift(), chain.shift())
  }
}

function interceptorsManner() {
  this.handler = []
}

interceptorsManner.prototype.use = function (fulfilled, rejected) {
  //将成功与失败的回调push到handler中
  this.handler.push({
    fulfilled: fulfilled,
    rejected: rejected
  })
}

//类似方法批量注册,实现多种请求
util.forEach(['get', 'post', 'delete'], (methods) => {
  Axios.prototype[methods] = function (url, config) {
    return this.request(
      util.merge(config || {}, {
        //合并
        method: methods,
        url: url
      })
    )
  }
})
posted @ 2022-05-12 17:22  时光凉忆  阅读(1433)  评论(0编辑  收藏  举报