当前位置: 首页 > article >正文

axios架构设计和原理

1. 前端请求方式

  • 原生XHR:最初,在Web开发的早期,前端请求库的唯一选择是使用XMLHttpRequest(XHR)对象。XHR提供了一种在浏览器中发起HTTP请求的方式,但使用XHR需要编写大量重复的代码,并且缺乏灵活性
  • jQuery Ajax:随着jQuery的兴起,jQuery Ajax成为了主流的前端请求库。jQuery Ajax使用简单,可以轻松地发送异步请求,并且具有良好的跨浏览器支持。它为开发人员提供了简单易用的API,并支持各种数据格式,例如JSON和XML。
  • Fetch API:Fetch API是浏览器内置的一种用于发起HTTP请求的API,它支持Promise,更加简洁易用。Fetch API基于标准的Promise接口,可以更好地支持异步请求,从而提高代码的可读性和可维护性。
  • Axios:Axios是一个基于Promise的HTTP客户端库,它提供了简单、一致的API,可以轻松地处理HTTP请求和响应。Axios可以用于浏览器和Node.js,并且可以与React、Vue等框架很好地配合使用。它支持拦截请求和响应,支持取消请求等高级功能。

2. axios是什么

axios是一个基于promise的网络请求库,它可以用于浏览器和nodejs当中。在不同环境,它所使用的请求API是不同的,在nodejs环境使用的node原生的http模块,而在浏览器中使用的是XMLHTTPRequest

3. axios的特性

  • 从浏览器创建 XMLHttpRequests
  • 从 node.js 创建 http 请求
  • 支持 Promise API
  • 拦截请求和响应
  • 转换请求和响应数据
  • 取消请求
  • 自动转换JSON数据
  • 客户端支持防御XSRF

4. axios的原理

axios整体架构:

在这里插入图片描述

4.1 axios的调用方式
// 第一种:直接调用
axios(config)
// 第二种:通过axios的属性方法调用
axios.get(url[, config])//'delete', 'get', 'head', 'options'请求方法一样的调用方式
axios.post(url[, data[, config]])// 'post', 'put', 'patch'请求方法永阳的调用方式

// 第三种:并行调用
axios.all([axios1, axios2, axios3]).then(axios.spread(function (axios1response, axios2response, axios3response) {
  // 三个请求现在都执行完成
}));
// 第四种:通过axios.create方法建立自定义全局默认配置的Axios实例
axios.create(config)
为什么 axios 既可以当函数调用,也可以当对象使用?
function createInstance(defaultConfig) {
  const context = new Axios(defaultConfig);
  const instance = bind(Axios.prototype.request, context);

  // Copy axios.prototype to instance
  utils.extend(instance, Axios.prototype, context);

  // Copy context to instance
  utils.extend(instance, context, null);

  // Factory for creating new instances
  instance.create = function create(instanceConfig) {
    return createInstance(mergeConfig(defaultConfig, instanceConfig));
  };

  return instance;
}

// Create the default instance to be exported
const axios = createInstance(defaults);

axios.create = function create(instanceConfig) {
  return createInstance(mergeConfig(axios.defaults, instanceConfig));
};

axios.all = function all(promises) {
  return Promise.all(promises);
};

axios.spread = function (callback) {
  return function wrap(arr) {
    return callback.apply(null, arr);
  };
}
export default axios

axios类:

class Axios {
  constructor(instanceConfig) {
    this.defaults = instanceConfig;
    this.interceptors = {
      request: new InterceptorManager(),
      response: new InterceptorManager()
    };
  }
  request(configOrUrl, config) {
    /*eslint no-param-reassign:0*/
    // Allow for axios('example/url'[, config]) a la fetch API
    if (typeof configOrUrl === 'string') {
      config = config || {};
      config.url = configOrUrl;
    } else {
      config = configOrUrl || {};
    }

    config = mergeConfig(this.defaults, config);
    // ....省略了一些代码
    
  }
}

utils.forEach(['delete', 'get', 'head', 'options'], function forEachMethodNoData(method) {
  Axios.prototype[method] = function(url, config) {
    return this.request(mergeConfig(config || {}, {
      method,
      url,
      data: (config || {}).data
    }));
  };
});
4.2 axios的拦截器

拦截器的使用:

// 请求拦截器
const requestInterceptor = axios.interceptors.request.use(config => {
    return config;
}, error => {
    return Promise.reject(error);
});

// 添加响应拦截器
const responseInterceptor = axios.interceptors.response.use(response => {
  return response;
}, error => {
  return Promise.reject(error);
});

// 移除拦截器
axios.interceptors.request.eject(requestInterceptor);

多个拦截器:
在这里插入图片描述

执行顺序:

  • 请求拦截器:先添加的后执行
  • 响应拦截器:先添加的先执行

拦截器的原理:

  1. 存储拦截器
class InterceptorManager {
  constructor() {
    this.handlers = [];
  }

  use(fulfilled, rejected, options) {
    this.handlers.push({
      fulfilled,
      rejected
    });
    return this.handlers.length - 1;
  }
  eject(id) {
    if (this.handlers[id]) {
      this.handlers[id] = null;
    }
  }
}

export default InterceptorManager;
  1. 建立promise链
class Axios {
  constructor() {
    this.interceptors = {
      request: new InterceptorManager(),
      response: new InterceptorManager()
    }
  }
  request(config) {
        const chain = [{
            onFulfilled: this.dispatchRequest,
            onRejected: null
        }]
        this.interceptors.request.interceptors.forEach((interceptor) => {
            interceptor && chain.unshift(interceptor)
        })

        this.interceptors.response.interceptors.forEach((interceptor) => {
            interceptor && chain.push(interceptor)
        })
        let promise = Promise.resolve(config);

        while (chain.length) {
            const { onFulfilled, onRejected } = chain.shift()!;
            promise = promise.then(onFulfilled, onRejected);
        }
        return promise
    }
}
4.3 cancelToken取消请求

取消请求用法:

// 第一种取消方法
const CancelToken = axios.CancelToken;
const source = CancelToken.source();

axios.get('/user/12345', {
  cancelToken: source.token
}).catch(function (thrown) {
  if (axios.isCancel(thrown)) {
    console.log('Request canceled', thrown.message);
  } else {
    // handle error
  }
});

source.cancel('Operation canceled by the user.');

// 第二种取消方法
const CancelToken = axios.CancelToken;
let cancel;

axios.get('/user/12345', {
  cancelToken: new CancelToken(function executor(c) {
    // An executor function receives a cancel function as a parameter
    cancel = c;
  })
});

// cancel the request
cancel();

取消请求实现:

export class Cancel {
    constructor(public reason: string) { }
}
export function isCancel(error: any) {
    return error instanceof Cancel;
}
export class CancelToken {
    public resolve: any;
    source() {
        return {
            token: new Promise((resolve) => {
                this.resolve = resolve;
            }),
            cancel: (reason: string) => {
                this.resolve(new Cancel(reason));
            }
        }
    }
}

// axios.js
axios.CancelToken = new CancelToken();
axios.isCancel = isCancel;

function dispatchRequest(config){
  // 发送xhr请求
   if (config.cancelToken) {
       config.cancelToken.then((reason: string) => {
          request.abort();
          reject(reason);
      });
   }
}

5. 其它请求库

umi-request,基于 fetch 封装, 兼具 fetch 与 axios 的特点, 旨在为开发者提供一个统一的 api 调用方式, 简化使用, 并提供诸如缓存, 超时, 字符编码处理, 错误处理等常用功能.

umi-request和fetch和axios的对比:

在这里插入图片描述


http://www.kler.cn/a/522444.html

相关文章:

  • Python GUI 开发 | Qt Designer — 工具介绍
  • 【C++题解】1393. 与7无关的数?
  • 神经网络|(七)概率论基础知识-贝叶斯公式
  • doris:Bitmap
  • 一个简单的自适应html5导航模板
  • 海外问卷调查渠道查如何设置:最佳实践+示例
  • 「数学::质数」分解质因子 / LeetCode 2521(C++)
  • 算法1-1 模拟与高精度
  • 35、【OS】【Nuttx】OSTest分析(1):stdio测试(五)
  • 青少年CTF练习平台 贪吃蛇
  • 函数与方法
  • 浅谈OceanBase旁路导入
  • 如何学习Java后端开发
  • js手撕 | 使用css画一个三角形 使用js修改元素样式 驼峰格式与“-”格式相互转化
  • QT交叉编译环境搭建(Cmake和qmake)
  • MCP Server 开发实战:无缝对接 LLM 和 Elasticsearch
  • 【深度学习】常见模型-自编码器(Autoencoder, AE)
  • python -m pip和pip的主要区别
  • 亚博microros小车-原生ubuntu支持系列:14雷达跟踪与雷达守卫
  • CAN波特率匹配
  • OPPO自研DataFlow架构与实践
  • RHEL封闭环境部署zabbix
  • 【数据资产】数据资产管理概述
  • Workerman和Swoole有什么区别
  • Verilog中if语句和case语句综合出的电路区别
  • RabbitMQ 多种安装模式