axios和fetch的实现原理以及区别,与XMLHttpRequest的关系,并结合react封装统一请求示例

Axios 和 Fetch 对比及统一请求封装

1. Axios 基础用法

1.1 安装和引入

javascript 复制代码
// 安装
npm install axios

// 引入
import axios from 'axios';

1.2 基本请求方法

javascript 复制代码
// GET 请求
axios.get('/api/users')
  .then(response => console.log(response.data))
  .catch(error => console.error(error));

// POST 请求
axios.post('/api/users', {
  name: 'John',
  age: 30
})
  .then(response => console.log(response.data))
  .catch(error => console.error(error));

// PUT 请求
axios.put('/api/users/1', {
  name: 'John',
  age: 31
});

// DELETE 请求
axios.delete('/api/users/1');

// 使用 async/await
async function fetchData() {
  try {
    const response = await axios.get('/api/users');
    console.log(response.data);
  } catch (error) {
    console.error(error);
  }
}

1.3 配置选项

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

// 请求配置
axios({
  method: 'post',
  url: '/api/users',
  data: {
    name: 'John',
    age: 30
  },
  headers: {
    'Content-Type': 'application/json'
  },
  timeout: 5000,
  withCredentials: true
});

// 创建实例
const instance = axios.create({
  baseURL: 'https://api.example.com',
  timeout: 5000,
  headers: {'X-Custom-Header': 'value'}
});

2. Fetch 基础用法

2.1 基本请求方法

javascript 复制代码
// GET 请求
fetch('/api/users')
  .then(response => response.json())
  .then(data => console.log(data))
  .catch(error => console.error(error));

// POST 请求
fetch('/api/users', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    name: 'John',
    age: 30
  })
})
  .then(response => response.json())
  .then(data => console.log(data))
  .catch(error => console.error(error));

// 使用 async/await
async function fetchData() {
  try {
    const response = await fetch('/api/users');
    const data = await response.json();
    console.log(data);
  } catch (error) {
    console.error(error);
  }
}

2.2 请求配置

javascript 复制代码
fetch('/api/users', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'Authorization': 'Bearer token'
  },
  body: JSON.stringify(data),
  mode: 'cors',
  credentials: 'include',
  cache: 'no-cache',
  redirect: 'follow'
});

3. Axios 和 Fetch 的主要区别

3.1 功能差异

  1. 请求/响应拦截
javascript 复制代码
// Axios 支持拦截器
axios.interceptors.request.use(config => {
  // 请求前处理
  return config;
}, error => {
  return Promise.reject(error);
});

axios.interceptors.response.use(response => {
  // 响应后处理
  return response;
}, error => {
  return Promise.reject(error);
});

// Fetch 需要自行封装
const fetchWithInterceptor = async (...args) => {
  // 请求前处理
  const response = await fetch(...args);
  // 响应后处理
  return response;
};
  1. 自动转换 JSON
javascript 复制代码
// Axios 自动转换 JSON
axios.get('/api/users')
  .then(response => console.log(response.data)); // 直接获取数据

// Fetch 需要手动转换
fetch('/api/users')
  .then(response => response.json())
  .then(data => console.log(data));
  1. 错误处理
javascript 复制代码
// Axios 统一处理错误
axios.get('/api/users')
  .catch(error => {
    if (error.response) {
      // 服务器响应错误
      console.log(error.response.status);
    } else if (error.request) {
      // 请求未收到响应
      console.log(error.request);
    } else {
      // 请求配置错误
      console.log(error.message);
    }
  });

// Fetch 需要手动检查状态
fetch('/api/users')
  .then(response => {
    if (!response.ok) {
      throw new Error(`HTTP error! status: ${response.status}`);
    }
    return response.json();
  })
  .catch(error => console.log(error));

3.2 浏览器支持

  • Fetch: 现代浏览器原生支持,但不支持 IE
  • Axios: 支持所有主流浏览器,包括 IE11

4. React 统一请求封装

4.1 基于 Axios 的封装

typescript 复制代码
// src/utils/request.ts
import axios, { AxiosInstance, AxiosRequestConfig, AxiosResponse } from 'axios';
import { message } from 'antd';

// 请求配置类型
interface RequestConfig extends AxiosRequestConfig {
  loading?: boolean;
  skipErrorHandler?: boolean;
}

// 响应数据类型
interface ResponseData<T = any> {
  code: number;
  data: T;
  message: string;
}

class Request {
  private instance: AxiosInstance;
  private loading: boolean;

  constructor() {
    this.instance = axios.create({
      baseURL: process.env.REACT_APP_API_URL,
      timeout: 10000,
      headers: {
        'Content-Type': 'application/json'
      }
    });
    this.loading = false;
    this.setupInterceptors();
  }

  private setupInterceptors() {
    // 请求拦截器
    this.instance.interceptors.request.use(
      (config: RequestConfig) => {
        // 添加 token
        const token = localStorage.getItem('token');
        if (token) {
          config.headers.Authorization = `Bearer ${token}`;
        }

        // 显示加载状态
        if (config.loading) {
          this.loading = true;
          // 可以使用 antd 的 loading 组件
        }

        return config;
      },
      error => {
        return Promise.reject(error);
      }
    );

    // 响应拦截器
    this.instance.interceptors.response.use(
      (response: AxiosResponse<ResponseData>) => {
        // 隐藏加载状态
        this.loading = false;

        const { code, data, message: msg } = response.data;

        // 处理业务错误
        if (code !== 0) {
          if (!response.config.skipErrorHandler) {
            message.error(msg || '请求失败');
          }
          return Promise.reject(new Error(msg || '请求失败'));
        }

        return data;
      },
      error => {
        // 隐藏加载状态
        this.loading = false;

        // 处理 HTTP 错误
        if (!error.config?.skipErrorHandler) {
          if (error.response) {
            switch (error.response.status) {
              case 401:
                message.error('未授权,请重新登录');
                // 可以在这里处理登出逻辑
                break;
              case 403:
                message.error('拒绝访问');
                break;
              case 404:
                message.error('请求的资源不存在');
                break;
              case 500:
                message.error('服务器错误');
                break;
              default:
                message.error(`请求失败: ${error.message}`);
            }
          } else {
            message.error('网络错误,请检查网络连接');
          }
        }

        return Promise.reject(error);
      }
    );
  }

  // 通用请求方法
  public async request<T = any>(config: RequestConfig): Promise<T> {
    try {
      const response = await this.instance.request<any, T>(config);
      return response;
    } catch (error) {
      return Promise.reject(error);
    }
  }

  // GET 请求
  public get<T = any>(url: string, config?: RequestConfig): Promise<T> {
    return this.request({ ...config, method: 'GET', url });
  }

  // POST 请求
  public post<T = any>(url: string, data?: any, config?: RequestConfig): Promise<T> {
    return this.request({ ...config, method: 'POST', url, data });
  }

  // PUT 请求
  public put<T = any>(url: string, data?: any, config?: RequestConfig): Promise<T> {
    return this.request({ ...config, method: 'PUT', url, data });
  }

  // DELETE 请求
  public delete<T = any>(url: string, config?: RequestConfig): Promise<T> {
    return this.request({ ...config, method: 'DELETE', url });
  }
}

export default new Request();

4.2 使用示例

typescript 复制代码
// src/api/user.ts
import request from '@/utils/request';

interface User {
  id: number;
  name: string;
  age: number;
}

export const userApi = {
  // 获取用户列表
  getUsers: () => request.get<User[]>('/api/users'),

  // 获取用户详情
  getUser: (id: number) => request.get<User>(`/api/users/${id}`),

  // 创建用户
  createUser: (data: Omit<User, 'id'>) => 
    request.post<User>('/api/users', data),

  // 更新用户
  updateUser: (id: number, data: Partial<User>) =>
    request.put<User>(`/api/users/${id}`, data),

  // 删除用户
  deleteUser: (id: number) =>
    request.delete(`/api/users/${id}`)
};

// 在组件中使用
import React, { useEffect, useState } from 'react';
import { userApi } from '@/api/user';

const UserList: React.FC = () => {
  const [users, setUsers] = useState<User[]>([]);

  useEffect(() => {
    const fetchUsers = async () => {
      try {
        const data = await userApi.getUsers();
        setUsers(data);
      } catch (error) {
        console.error('Failed to fetch users:', error);
      }
    };

    fetchUsers();
  }, []);

  const handleCreateUser = async () => {
    try {
      const newUser = await userApi.createUser({
        name: 'John',
        age: 30
      });
      setUsers(prev => [...prev, newUser]);
    } catch (error) {
      console.error('Failed to create user:', error);
    }
  };

  return (
    <div>
      {/* 渲染用户列表 */}
    </div>
  );
};

export default UserList;

5. 最佳实践建议

1. 选择建议

  • 小型项目:使用 Fetch 足够
  • 大型项目:推荐使用 Axios(功能更完善)
  • 需要兼容 IE:必须使用 Axios

2. 性能优化

  • 合理使用请求取消
  • 实现请求缓存
  • 避免重复请求

3. 安全考虑

  • 统一处理敏感信息
  • 实现请求超时
  • CSRF 防护

4. 开发建议

  • 使用 TypeScript 增加类型安全
  • 集中管理 API 请求
  • 做好错误处理
  • 添加请求日志

6. fetch实现原理

fetch 是一种用于在浏览器中发起 HTTP 请求并获取响应的 API,它是 XMLHttpRequest 的现代替代品。fetch 基于 Promise,使得异步代码更加简洁和易于理解。它的实现原理是利用浏览器提供的低级 API 来执行 HTTP 请求和处理响应。

1. fetch 的基本使用

fetch 接口允许你通过网络发起请求并返回响应,它的基本语法如下:

javascript 复制代码
fetch(url, options)
  .then(response => response.json())  // 或者 response.text(), response.blob() 等
  .then(data => console.log(data))
  .catch(error => console.log(error));

url:要请求的资源地址。

options(可选):一个包含配置选项的对象,用于配置请求方法、请求头、请求体等。

2. fetch 的底层实现原理

fetch 是基于浏览器的 Fetch API 实现的,它的实现原理依赖于以下几个关键步骤:

2.1 发起 HTTP 请求

当你调用 fetch 时,浏览器通过 HTTP 协议 向目标 URL 发送请求。这个请求可以是 GET、POST、PUT 等类型,并且可以包含请求头和请求体(例如,POST 请求通常包含数据)。

在底层,fetch 会使用 浏览器的网络栈(例如,TCP/IP 协议、TLS/SSL 等)通过 DNS 查询目标服务器的 IP 地址,建立网络连接,并发送 HTTP 请求。

2.2 异步请求与 Promise

fetch 是基于 Promise 的,它允许我们在请求完成后异步处理结果。这意味着当你调用 fetch 时,浏览器会立即发起请求并返回一个未完成的 Promise。then 方法中传入的回调函数会在请求完成时被调用,而 catch 会捕获任何可能发生的错误。

例如:

javascript 复制代码
fetch(url)   // 发起请求并返回一个 Promise
  .then(response => {
    console.log("Response received");
    return response.json();   // 解析 JSON 数据
  })
  .catch(error => console.log(error));  // 捕获错误

在浏览器中,fetch 实际上是通过 JavaScript 事件循环机制调度 HTTP 请求,它不会阻塞主线程。由于 fetch 是异步的,它允许页面在等待请求返回的同时执行其他任务。

2.3 请求头与配置

在 fetch 请求中,你可以通过 options 对象来配置请求。例如,你可以设置请求方法(GET、POST 等),设置请求头,发送请求体等。

javascript 复制代码
const options = {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({ key: 'value' })  // 请求体
};

fetch(url, options)
  .then(response => response.json())
  .then(data => console.log(data))
  .catch(error => console.log(error));

这些选项会通过浏览器的 HTTP 客户端 发送到服务器。浏览器会根据请求的类型和配置,构建相应的 HTTP 请求头部和请求体。

2.4 响应处理

fetch 发起请求并接收响应时,它返回的 response 对象代表 HTTP 响应。这些响应信息包括状态码、响应头和响应体内容。

javascript 复制代码
fetch(url)
  .then(response => {
    if (!response.ok) {
      throw new Error('Network response was not ok');
    }
    return response.json();   // 返回 JSON 数据
  })
  .then(data => console.log(data))
  .catch(error => console.log(error));

response.ok 是一个布尔值,表示响应是否成功(状态码 200 到 299 表示成功)。response.json()、response.text()、response.blob() 等方法允许你读取响应体内容。

2.5 CORS(跨域资源共享)

当你发起跨域请求时,浏览器会处理跨域资源共享(CORS)问题。fetch 会自动处理 预检请求(OPTIONS 请求),并根据目标服务器的 CORS 策略决定是否允许访问。

如果服务器响应了正确的 CORS 头部,浏览器会允许访问并返回资源。

如果服务器未响应适当的 CORS 头部,fetch 请求将被阻止,并抛出一个错误。

3. 底层实现

从实现角度来看,fetch 依赖于浏览器内部的网络通信堆栈。以下是 fetch 实现的几个关键点:

请求建立:

当 fetch 被调用时,浏览器会通过其网络库(如 libcurl 或原生的浏览器网络栈)解析 URL、进行 DNS 查询、建立 TCP 连接。

发送请求:

浏览器根据配置(如请求方法、头部、体等)构造 HTTP 请求并发送到目标服务器。

等待响应:

请求发送后,浏览器会等待响应。浏览器根据响应的 HTTP 状态码和头部信息来判断请求是否成功。

解析响应:

浏览器收到响应后,会将响应内容存储在 response 对象中,并提供如 response.json()、response.text() 等方法来解析响应内容。

事件循环和 Promise:

fetch 的操作是异步的,基于 事件循环 机制和 Promise。当响应可用时,相关的 .then() 或 .catch() 方法会被执行。

4. 与 XMLHttpRequest 的对比

fetch 与传统的 XMLHttpRequest (XHR) 相比,有以下几个主要优势:

Promise 支持:fetch 基于 Promise,使得代码更加简洁和易于理解,避免了回调地狱。

简洁的 API:fetch 的 API 更加简洁,尤其是在处理响应体时。你只需要使用 .json()、.text()、.blob() 等方法来解析响应内容,而 XMLHttpRequest 需要更多的手动配置。

默认不发送 Cookies:fetch 默认不会发送跨域请求时的 Cookies(除非配置了 credentials 选项)。而 XMLHttpRequest 默认会自动发送 Cookies。

支持流式传输:fetch 支持响应流(ReadableStream),允许更高效地处理大文件和流式响应。

5. 总结

fetch 是现代浏览器中用来发起 HTTP 请求的原生 API,它依赖浏览器的网络堆栈来执行低级别的请求操作。通过基于 Promise 的设计,fetch 提供了更清晰的异步操作流程。它的实现利用了浏览器的网络层和异步编程机制,能够有效处理 HTTP 请求、响应、CORS 等问题。

7. fetch和XMLHttpRequest区别

fetch 和 XMLHttpRequest 都是浏览器提供的用于发起 HTTP 请求的 API,尽管它们的目的相同------发送和接收数据------它们在设计、功能、使用方式和底层实现上有许多差异。下面是它们之间的关系和主要区别:

1. 关系:

功能相似:fetch 和 XMLHttpRequest 都用于从客户端(浏览器)发送 HTTP 请求到服务器,并获取响应。这意味着它们都可以用来发送数据(如表单提交、获取 API 数据等)。

底层原理:虽然 fetch 是现代浏览器的标准 API,而 XMLHttpRequest 是较旧的标准 API,但它们都通过浏览器的网络堆栈与服务器通信。fetch 是 XMLHttpRequest 的替代品,提供了更现代、更简洁的 API。

异步操作:fetch 和 XMLHttpRequest 都是异步的,可以执行异步 HTTP 请求,但 fetch 使用了更现代的 Promise 机制,而 XMLHttpRequest 主要基于回调(callback)机制。

2. 主要区别:

2.1 API 风格和易用性

fetch:

基于 Promise,支持链式调用,使代码更加简洁和易于维护。

语法简洁,只返回响应的 response 对象,不会自动处理请求错误(需要手动检查状态码和抛出错误)。

采用更现代的设计,支持 async/await,使得处理异步操作更自然。

示例:

javascript 复制代码
fetch(url)
  .then(response => response.json())
  .then(data => console.log(data))
  .catch(error => console.error(error));

XMLHttpRequest:

基于回调机制,使用 onreadystatechange 或 onload 事件处理响应,导致代码更复杂,容易出现回调地狱(callback hell)。

没有内置的 Promise 支持,因此通常与回调函数或外部库(如 jQuery)一起使用来简化操作。

示例:

javascript 复制代码
const xhr = new XMLHttpRequest();
xhr.open('GET', url, true);
xhr.onreadystatechange = function() {
  if (xhr.readyState === 4 && xhr.status === 200) {
    const data = JSON.parse(xhr.responseText);
    console.log(data);
  }
};
xhr.send();
2.2 请求和响应的处理

fetch:

返回的是一个 Promise,这意味着响应是异步处理的,并且通过 then() 或 async/await 进行响应数据的处理。

不会自动抛出 HTTP 错误(如 404 或 500),需要手动检查 response.ok 或 response.status 来判断请求是否成功。

XMLHttpRequest:

使用事件回调处理响应,通常是通过 onload 或 onreadystatechange 来处理请求的响应。

自动将响应文本(responseText)作为字符串返回,解析 JSON 或其他数据类型需要手动处理。

XMLHttpRequest 会自动在请求失败时调用 onerror 回调函数。

2.3 错误处理

fetch:

默认不会对 HTTP 错误(如 404、500)抛出错误,只有网络错误(例如无网络连接)才会触发 .catch()。

需要手动检查 response.ok 或 response.status 来判断响应是否成功。

示例:

javascript 复制代码
fetch(url)
  .then(response => {
    if (!response.ok) {
      throw new Error('Network response was not ok');
    }
    return response.json();
  })
  .then(data => console.log(data))
  .catch(error => console.error('Fetch error:', error));

XMLHttpRequest:

XMLHttpRequest 会根据请求的状态码来执行相应的回调方法,通常是通过检查 xhr.status 来判断请求是否成功。

2.4 请求体处理

fetch:

直接支持通过 body 选项发送请求体(如发送 JSON 数据),且支持 FormData、Blob、ArrayBuffer 等多种数据类型。

通过 headers 选项配置请求头。

示例:

javascript 复制代码
const options = {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({ key: 'value' })
};

fetch(url, options)
  .then(response => response.json())
  .then(data => console.log(data));

XMLHttpRequest:

需要手动设置请求头,并使用 xhr.send() 发送请求体。

对发送 JSON 数据通常需要手动字符串化,并设置 Content-Type 头部。

示例:

javascript 复制代码
const xhr = new XMLHttpRequest();
xhr.open('POST', url, true);
xhr.setRequestHeader('Content-Type', 'application/json');
xhr.send(JSON.stringify({ key: 'value' }));
2.5 跨域请求(CORS)

fetch:

默认支持跨域请求(CORS),但需要服务器在响应中包含适当的 CORS 头部。

可以通过 credentials 选项来控制是否发送 Cookies、授权头等。

示例:

javascript 复制代码
fetch(url, { credentials: 'same-origin' })
  .then(response => response.json())
  .then(data => console.log(data))
  .catch(error => console.error(error));

XMLHttpRequest:

支持跨域请求,但需要手动处理 CORS(通常在跨域时需要服务器添加 CORS 头部)。

默认发送跨域请求时不会携带 Cookies。

2.6 流式响应(Streams)

fetch:

支持流式响应,允许逐步处理大文件或大数据集。响应体是一个 ReadableStream,这使得你可以逐步读取数据而不是一次性获取整个响应。

示例:

javascript 复制代码
fetch(url)
  .then(response => {
    const reader = response.body.getReader();
    reader.read().then(function processText({ done, value }) {
      if (done) return;
      console.log(value);
      reader.read().then(processText);
    });
  });

XMLHttpRequest:

不支持流式响应。它需要等待整个响应下载完毕才会调用回调函数。

2.7 支持情况

fetch:

fetch 是一个现代的 API,已被大多数现代浏览器(如 Chrome、Firefox、Edge、Safari)支持,但在一些旧版本的浏览器中(如 Internet Explorer)不支持。

需要通过 polyfill 来在不支持的浏览器中使用。

XMLHttpRequest:

XMLHttpRequest 在所有主流浏览器中都被广泛支持,包括旧版本的浏览器(如 Internet Explorer)。

3. 总结

fetch 是一个现代的、基于 Promise 的 API,具有更简洁的语法和更强大的功能,如流式响应、异步操作的简化、更易于使用的错误处理等。

XMLHttpRequest 是较老的 API,基于回调机制,功能上不如 fetch 灵活和简洁,但仍然被广泛使用,特别是在一些较旧的浏览器中。

尽管 fetch 是 XMLHttpRequest 的现代替代品,XMLHttpRequest 仍然存在于许多遗留的代码中。fetch 是未来的主流选择,而 XMLHttpRequest 在许多场景下也依然可用,尤其是与旧版本的浏览器兼容时。

8. Axios的实现原理

Axios 是一个基于 Promise 的 JavaScript 库,用于简化浏览器和 Node.js 环境中的 HTTP 请求。Axios 主要通过封装 XMLHttpRequest 或 Node.js 的 http/https 模块 来实现对 HTTP 请求的支持,而 并没有直接封装 fetch。

1. 浏览器中的实现

在 浏览器环境 中,Axios 默认使用 XMLHttpRequest 进行 HTTP 请求。XMLHttpRequest 是浏览器中较早的一个用于发起 HTTP 请求的 API,广泛支持,并且可以处理浏览器中常见的 HTTP 请求需求。

使用 XMLHttpRequest:

在浏览器环境中,Axios 封装了 XMLHttpRequest,对其进行了改造和增强,使得 API 使用更加简洁。

通过封装,Axios 提供了基于 Promise 的异步编程模型,支持链式调用、请求和响应拦截、请求取消、自动转换 JSON 数据等功能。

Axios 还会自动处理一些常见的错误情况(如 404、500 错误)并通过 Promise 抛出异常,方便开发者统一处理。

示例:Axios 在浏览器中的基本实现(简化版)

javascript 复制代码
// 伪代码,简化版
function axiosRequest(config) {
  return new Promise((resolve, reject) => {
    const xhr = new XMLHttpRequest();
    xhr.open(config.method, config.url, true);
    
    // 设置请求头
    Object.keys(config.headers).forEach(key => {
      xhr.setRequestHeader(key, config.headers[key]);
    });

    xhr.onload = function () {
      if (xhr.status >= 200 && xhr.status < 300) {
        resolve(xhr.response);  // 请求成功,解析响应
      } else {
        reject(new Error('Request failed with status code ' + xhr.status));  // 请求失败
      }
    };

    xhr.onerror = function () {
      reject(new Error('Network Error'));  // 网络错误
    };

    // 发送请求
    xhr.send(config.data);
  });
}

2. Node.js 中的实现

在 Node.js 环境 中,Axios 不是使用 XMLHttpRequest,因为 XMLHttpRequest 是浏览器专有的 API,而是使用 Node.js 原生的 http 和 https 模块 来发起 HTTP 请求。

使用 http/https 模块:

在 Node.js 中,Axios 使用 Node.js 自带的 HTTP 库 (http 或 https),这些库非常适合用于服务器端请求。

Axios 将 HTTP 请求和响应处理的过程封装为 Promise,允许开发者通过链式调用来处理异步操作。

示例:Axios 在 Node.js 中的基本实现(简化版)

javascript 复制代码
// 伪代码,简化版
const http = require('http');
const https = require('https');

function axiosRequest(config) {
  return new Promise((resolve, reject) => {
    const client = config.url.startsWith('https') ? https : http;
    
    const req = client.request(config.url, { method: config.method, headers: config.headers }, (res) => {
      let data = '';
      
      // 接收数据
      res.on('data', chunk => {
        data += chunk;
      });
      
      res.on('end', () => {
        if (res.statusCode >= 200 && res.statusCode < 300) {
          resolve(data);  // 请求成功,解析响应
        } else {
          reject(new Error('Request failed with status code ' + res.statusCode));  // 请求失败
        }
      });
    });

    req.on('error', (e) => {
      reject(e);  // 网络错误
    });

    // 发送请求
    req.write(config.data);
    req.end();
  });
}

3. Axios 与 fetch 的关系

Axios 和 fetch 都是基于 Promise 的异步 API,功能上有很多相似之处,例如:

都支持发起 GET、POST 等 HTTP 请求。

都支持 Promise,允许链式调用。

都允许设置请求头、请求体、超时等配置。

然而,Axios 并没有直接基于 fetch 封装。虽然 fetch 是现代浏览器中用于发起 HTTP 请求的推荐 API,Axios 仍然选择使用 XMLHttpRequest 在浏览器中发起请求,原因如下:

更广泛的兼容性:XMLHttpRequest 在较旧的浏览器中也有很好的支持,尤其是在像 Internet Explorer 这样的旧版浏览器中。fetch 相对较新,部分旧浏览器不支持,需要 polyfill 来补充支持。

功能扩展:Axios 提供了一些 fetch 不直接支持的功能,比如请求拦截器、响应拦截器、自动转换 JSON 数据、请求取消、默认超时处理等。

简化错误处理:fetch 本身不会自动抛出 HTTP 错误(如 404 或 500 错误),需要开发者手动检查 response.ok。而 Axios 会根据 HTTP 状态码自动抛出异常,简化了错误处理。

4. 总结

Axios 的实现原理:Axios 在 浏览器中使用 XMLHttpRequest,在 Node.js 中使用 http 或 https 模块 来发起 HTTP 请求。

Axios 并没有封装 fetch,尽管它与 fetch 有一些相似之处。Axios 提供了更多的功能(如请求拦截、响应拦截、自动 JSON 转换等),并选择了在浏览器中使用 XMLHttpRequest 来确保更广泛的兼容性。

相关推荐
码农小菲3 分钟前
vue3-dom-diff算法
开发语言·javascript·算法
有心还是可以做到的嘛3 分钟前
Vue3中的watch函数
前端·javascript·vue.js
三天不学习4 分钟前
Vue Router v3.x 迁移到 v4.x(两者的区别)【路由篇】
前端·javascript·vue.js·router
大G哥7 分钟前
Tailwind CSS 实战:深色模式设计与实现
前端·css
古怪今人14 分钟前
前端同步发送HTTP请求 Ajax、Fetch和Axios实现HTTP同步请求
前端·http·ajax
时间sk20 分钟前
CSS——9.ID选择器
前端·javascript·css
_Jyann_24 分钟前
css如何选择元素的最后一个并设置样式
前端·javascript·css
开心工作室_kaic41 分钟前
springboot571基于协同过滤算法的私人诊所管理系统(论文+源码)_kaic
前端·数据库·vue.js·后端·html5
✎﹏ℳ๓₯㎕1 小时前
vue使用keep-alive实现页面前进刷新,后退缓存
前端·vue.js·缓存
onejason2 小时前
如何利用PHP爬虫批量获取商品信息
前端·php