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 来确保更广泛的兼容性。

相关推荐
李少兄6 小时前
JavaScript 数据类型完全指南
开发语言·javascript·ecmascript
Java陈序员7 小时前
轻量运维面板!一款现代化的服务器控制面板工具!
运维·服务器·python·react.js·github
尾善爱看海7 小时前
前端算法与手写题集
前端·算法
徐小夕8 小时前
JitWord 4.0 万字分享:从协同工具到AI Word操作系统,聊聊3年产品创业史
前端·vue.js·后端
shmily麻瓜小菜鸡9 小时前
JS/TS 易踩坑知识点 — 模块化与工程化类
开发语言·javascript·ecmascript
萧鼎9 小时前
Python 高性能Web框架神器 FastAPI:自动生成API文、基于Pydant、异步请求处理全搞定
前端·python·fastapi
IT_陈寒10 小时前
Redis误用keys命令把生产环境搞崩了,血的教训
前端·人工智能·后端
计算机魔术师10 小时前
5000亿估值冲刺科创板,DeepSeek 为何急着上市?
前端
我血条子呢10 小时前
前端解析word方案
前端·word
kyriewen10 小时前
我用 AI 写完一个需求后才发现,最难的不是 prompt,而是验收
前端·程序员·ai编程