前端的你应该知道的九种请求方式

浏览器中用于发起网络请求的 API 主要包括以下几种:

  1. XMLHttpRequest:这是一个老牌的 API,用于在浏览器和服务器之间发送 HTTP 请求。它支持异步请求,并可以通过设置回调函数来处理响应。尽管它已经被更现代的 API 取代,但在一些旧的浏览器或特定的场景中仍然有用。

    对于前端开发的我们来说,这个API再熟悉不过了,XHR 是最早接触到的网络请求 API,可以说是"老朋友"了。在很多老项目中,我们和后端沟通基本都用它。在我们平常所接触到的项目中,很多都是使用的Axios,在浏览器中,Axios底层也是使用了XMLHttpRequest对象来发送HTTP请求。

  2. Fetch:Fetch 是一个现代、功能强大的网络 API,它使用 Promise 使异步操作更加容易。Fetch 提供了更简洁的语法和更好的错误处理机制,并支持发送和接收各种类型的数据(如 JSON、文本、Blob 等)。

    Fetch 可以说是网络请求的"新宠",不仅语法简洁优雅,性能也非常出色。很多开发者都选择 Fetch 作为 XMLHTTPRequest 的替代方案,特别是在处理复杂的异步操作时,Fetch 显得更加得心应手。值得一提的是,Fetch的性能是要强于XMLHttpRequest。

  3. Axios:虽然 Axios 不是浏览器原生的 API,但它是一个流行的基于 Promise 的 HTTP 客户端库,可以在浏览器和 Node.js 中使用。Axios 提供了丰富的功能,如拦截请求和响应、取消请求、转换请求和响应数据等。

    前端项目中,尤其是 Vue 和 React 项目,Axios 几乎成了标配。它的功能强大,使用简单,很多开发者很喜欢这个请求库。

  4. jQuery.ajax :如果你正在使用 jQuery 这个 JavaScript 库,那么你可以使用它的 $.ajax() 方法来发送 HTTP 请求。这个方法非常灵活,支持多种请求类型,并且可以处理各种格式的数据。然而,随着现代 JavaScript 的发展和其他更简洁的 API 的出现,jQuery.ajax 的使用已经逐渐减少。

    jQuery,在我刚入行的时期算是统领前端开发,什么都可以jq一把梭。虽然现在国内jq的使用变少了很多,但是它依旧是一个很不错的库。

  5. Beacon APInavigator.sendBeacon() 方法允许异步地发送少量数据到服务器,通常用于在页面卸载时发送分析或诊断信息。这个方法确保数据发送成功,即使页面已经关闭或用户已经导航到其他页面。

    Beacon API 可以说是"默默无闻"的小帮手,特别适合在页面关闭或跳转时发送一些统计数据。不过,我自己学过但还没用过,希望以后有机会实践一下。

  6. WebSocket API:WebSocket 提供了一个全双工的通信通道,允许浏览器和服务器之间进行长时间的实时数据交换。这不同于传统的 HTTP 请求,HTTP 请求通常是客户端发起并等待服务器响应的模式。

    实时通信,像我们一些告警需求,不是用的轮询就是用的WebSockets。

  7. Server-Sent Events (SSE) :服务器发送事件允许服务器向客户端推送实时事件。与 WebSockets 不同,SSE 是单向的,只允许服务器向客户端发送数据。SSE 基于 HTTP,因此它们比 WebSockets 更简单,并且能够在现有的 HTTP 基础设施上工作。

    SSE 是一个简单实用的好方案,对于需要服务器单向推送数据的场景非常合适,比如实时更新股票价格。比起轮询和 WebSocket,SSE 的实现更简单,而且性能也不错。

  8. XMLHttpRequest Level 2(包括 FormData 和 Blob 对象):虽然这仍然是 XMLHttpRequest 的一部分,但值得注意的是,XMLHttpRequest Level 2 引入了一些改进和新功能,如 FormData 和 Blob 对象,它们使得发送表单数据和二进制数据更加容易。

    XMLHttpRequest Level 2 是老朋友的"进阶版",增加了很多实用功能。虽然它已经不再是最热门的选择,但在处理文件上传和复杂数据提交时,仍然是一个不错的工具。

  9. WebRTC (Web Real-Time Communication) :虽然 WebRTC 主要用于实时音频、视频和数据通信,但它也可以用于在浏览器之间建立点对点(peer-to-peer)的连接,并通过这些连接发送数据。这不是一个典型的"请求-响应"模型,而是一种更复杂的通信协议。

    WebRTC,大多数都用于音视频,有去了解过这方面的知识,给我的感觉就是,和前端开发不像是一个赛道,但是还是挺好玩的,

1. XMLHttpRequest

XMLHttpRequest (XHR) 是 JavaScript 中用于与服务器进行异步通信的 API。它允许我们在不刷新页面的情况下从服务器获取数据或向服务器发送数据。

XHR 对象可用于执行以下操作:

  • 从服务器获取数据
  • 向服务器发送数据
  • 上传文件
  • 监控请求进度
  • 处理服务器响应

这些也是与服务器进行异步通信的 API的基础功能。

1.1 XHR 的优点

XHR 具有以下优点:

  • 异步:XHR 请求不会阻塞页面渲染

  • 灵活:XHR 可用于执行各种操作

  • 强大:XHR 可用于上传文件和监控请求进度

1.2 XHR 的缺点

XHR 具有以下缺点:

  • 复杂:XHR 的 API 比较复杂
  • 不支持跨域请求:XHR 默认不支持跨域请求

默认不支持跨域请求的原因是浏览器为了安全,实施了同源策略(Same-origin policy)。

**

**

XHR 还支持以下高级用法:

  • 跨域请求:使用 CORS 允许跨域请求

  • 上传文件:使用 FormData 对象上传文件

  • 监控请求进度:使用 xhr.upload 对象监控请求进度

1.3 创建 XMLHttpRequest 对象

这是使用 XMLHttpRequest 的第一步。通过 new XMLHttpRequest() 可以创建一个新的 XMLHttpRequest 对象。

ini 复制代码
const xhr = new XMLHttpRequest();

1.4 初始化请求

使用 open 方法来初始化请求。它有三个主要参数:请求方法(GET, POST 等)、请求URL,以及是否异步(布尔值)。

kotlin 复制代码
xhr.open('GET', 'https://www.feng.com/data', true);

参数说明

  1. method:

    • 指定HTTP请求方法。

    • 常用方法包括:

      • "GET":从服务器获取数据。
      • "POST":向服务器发送数据。
      • "PUT":更新服务器上的数据。
      • "DELETE":删除服务器上的数据。
      • "HEAD":与GET类似,但只请求响应头。
  2. url:

    • 指定请求的目标URL。
    • 可以是相对路径(如 /data)或者绝对路径(如 https://api.example.com/data)。
  3. async:

    • 一个布尔值,指定请求是否异步执行。
    • 默认为 true
    • 如果设置为 false,请求会同步执行,浏览器会在请求完成之前被阻塞(不推荐使用,因为会影响用户体验)。
  4. user:

    • 一个可选参数,用于指定HTTP身份验证的用户名。
  5. password:

    • 一个可选参数,用于指定HTTP身份验证的密码。

HTTP 请求方法

1.5 设置请求头

使用 setRequestHeader 方法来设置请求头,这在发送POST请求或需要特定的请求头时特别有用。

arduino 复制代码
xhr.setRequestHeader('Content-Type', 'application/json');
  • 常用的请求头包括 Content-Type(指定请求体的媒体类型)、Authorization(授权信息)等。

常见HTTP请求头

1.6 发送请求

使用 send 方法来发送请求。对于GET请求,可以不传递参数;对于POST请求,可以传递请求体数据。

ini 复制代码
xhr.send();

对于POST请求,传递请求体数据:

ini 复制代码
const data = JSON.stringify({ name: 'Feng', age: 26 });
xhr.send(data);

1.7 处理响应

使用 onreadystatechange 事件处理响应。每当 readyState 属性改变时,onreadystatechange 事件会被触发。可以通过检查 readyStatestatus 来确定请求的状态和结果。

ini 复制代码
xhr.onreadystatechange = function() {
    if (xhr.readyState === 4) { // 请求完成
        if (xhr.status === 200) { // 成功
            console.log(xhr.responseText);
        } else {
            console.error('Error:', xhr.statusText);
        }
    }
};

readyState 属性:

readyState 属性表示请求的状态。它有五个可能的值:

  • 0 (UNSENT): 代理已被创建,但尚未调用 open 方法。
  • 1 (OPENED): open 方法已经被调用。
  • 2 (HEADERS_RECEIVED): send 方法已经被调用,并且头部和状态已经可获得。
  • 3 (LOADING): 下载中;responseText 属性已经包含部分数据。
  • 4 (DONE): 下载操作已完成。

status 属性:

status 属性表示HTTP状态码。例如:

  • 200 (OK): 请求成功。
  • 404 (Not Found): 请求的资源未找到。
  • 500 (Internal Server Error): 服务器错误。

1.8 responseText 和 responseXML 属性

  • responseText: 返回字符串形式的响应数据,适用于大多数情况。

  • responseXML: 返回解析后的XML文档对象,适用于返回XML数据的情况。

1.9 异步与同步请求

  • 异步请求 : open 方法的 async 参数为 true。这是推荐的方式,因为它不会阻塞浏览器的UI线程。
  • 同步请求 : open 方法的 async 参数为 false。这种方式会阻塞浏览器的UI线程,直到请求完成,不推荐使用。

同步请求很少用到,但是也不是没有使用场景。

1.10 处理错误

可以在 onreadystatechange 事件处理程序中检查状态码,并处理可能的错误。

ini 复制代码
xhr.onreadystatechange = function() {
    if (xhr.readyState === 4) {
        if (xhr.status === 200) {
            console.log(xhr.responseText);
        } else {
            console.error('Error:', xhr.status, xhr.statusText);
        }
    }
};

1.11 其他常用方法和属性

  • abort(): 取消当前请求。

  • getAllResponseHeaders(): 获取所有响应头。

  • getResponseHeader(header): 获取指定的响应头。

1.12 跨域请求

由于同源策略的限制,跨域请求需要服务器设置CORS(Cross-Origin Resource Sharing)头。示例如下:

kotlin 复制代码
xhr.open('GET', 'https://www.feng.com/data', true);
xhr.setRequestHeader('Origin', 'https://yourdomain.com');
xhr.send();

服务器需要返回允许跨域的头部:

makefile 复制代码
Access-Control-Allow-Origin: https://yourdomain.com
Access-Control-Allow-Methods: GET, POST
Access-Control-Allow-Headers: Content-Type

1.13 示例代码

GET 请求示例

ini 复制代码
const xhr = new XMLHttpRequest();
xhr.open('GET', 'https://www.feng.com/data', true);

xhr.onreadystatechange = function() {
    if (xhr.readyState === 4) {
        if (xhr.status === 200) {
            console.log(JSON.parse(xhr.responseText));
        } else {
            console.error('Error:', xhr.statusText);
        }
    }
};

xhr.send();

POST 请求示例

ini 复制代码
const xhr = new XMLHttpRequest();
xhr.open('POST', 'https://www.feng.com/data', true);
xhr.setRequestHeader('Content-Type', 'application/json');

xhr.onreadystatechange = function() {
    if (xhr.readyState === 4) {
        if (xhr.status === 200) {
            console.log(JSON.parse(xhr.responseText));
        } else {
            console.error('Error:', xhr.statusText);
        }
    }
};

const data = JSON.stringify({ name: 'Feng', age: 26 });
xhr.send(data);

2. Fetch API

Fetch API 是一种现代化的 JavaScript 接口,用于执行网络请求。它提供了一个更强大和灵活的方式来发出网络请求和处理响应,取代了旧有的 XMLHttpRequest(XHR)API。Fetch API 采用基于 Promise 的设计,使异步请求处理更加简洁和直观。

很推荐大家有机会可以在项目里使用Fetch。

2.1 Fetch API 的优点

  1. 简洁的语法:Fetch API 使用 Promise,大大简化了异步请求的代码。

  2. 支持更多功能:Fetch API 支持跨域请求、流媒体、请求和响应对象的完全控制等高级功能。

  3. 一致的接口:Fetch API 提供了一致且统一的请求和响应处理接口。

  4. 更好的错误处理:Promise 使得错误处理更加清晰和易于管理。

2.2 Fetch API 的缺点

  1. 不支持同步请求:Fetch API 只能用于异步请求,不支持同步请求。
  2. CORS 限制:Fetch API 遵循同源策略,跨域请求需要服务器配置 CORS(Cross-Origin Resource Sharing)。
  3. 复杂的流媒体处理:对于流媒体处理,Fetch API 相比 XHR 需要更多的代码处理。

有的小伙伴可能会想,是不是可以用async和await代替,但是呢,async和await并不会让fetch请求变成同步,只是会让请求看起来像是同步的,这里的异步是指会在异步环境中运行,并不会堵塞其他代码。
具体可以参考我的另一篇文章:juejin.cn/post/703921...

2.3 Fetch API 的用法

Fetch API 的基本用法涉及创建一个网络请求并处理响应。它返回一个 Promise,该 Promise 会在请求完成后解析为一个 Response 对象。

基本用法

javascript 复制代码
fetch('https://www.Feng.com/data')
  .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('There was a problem with the fetch operation:', error);
  });

创建请求

Fetch API 的 fetch 方法可以接受两个参数:请求的 URL 和可选的配置对象。配置对象允许指定请求方法、请求头、请求体等。

javascript 复制代码
fetch('https://www.Feng.com/data', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({ name: 'Feng', age: 26 })
})
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error('Error:', error));

请求方法

Fetch API 支持各种 HTTP 请求方法,包括 GET、POST、PUT、DELETE 等。以下是一些常见的请求方法及其示例。

typescript 复制代码
// GET 请求
fetch('https://www.Feng.com/data')
  .then(response => response.json())
  .then(data => console.log(data))
  .catch(error => console.error('Error:', error));

// POST 请求
fetch('https://www.Feng.com/data', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({ name: 'Feng', age: 26 })
})
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error('Error:', error));

// PUT 请求
fetch('https://www.Feng.com/data/1', {
  method: 'PUT',
  headers: {
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({ name: 'Feng', age: 26 })
})
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error('Error:', error));

// DELETE 请求
fetch('https://www.Feng.com/data/1', {
  method: 'DELETE'
})
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error('Error:', error));

设置请求头

可以通过配置对象的 headers 属性来设置请求头。常用的请求头包括 Content-Type、Authorization 等。

typescript 复制代码
fetch('https://www.Feng.com/data', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'Authorization': 'Bearer token'
  },
  body: JSON.stringify({ name: 'Feng', age: 26 })
})
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error('Error:', error));

处理响应

Fetch API 的 Response 对象提供了多种方法来处理响应数据。常用的方法包括 json()、text()、blob() 等。

ini 复制代码
// 处理 JSON 响应
fetch('https://www.Feng.com/data')
  .then(response => response.json())
  .then(data => console.log(data))
  .catch(error => console.error('Error:', error));

// 处理文本响应
fetch('https://www.Feng.com/data')
  .then(response => response.text())
  .then(data => console.log(data))
  .catch(error => console.error('Error:', error));

// 处理 Blob 响应
fetch('https://www.Feng.com/data')
  .then(response => response.blob())
  .then(blob => {
    const url = URL.createObjectURL(blob);
    const img = document.createElement('img');
    img.src = url;
    document.body.appendChild(img);
  })
  .catch(error => console.error('Error:', error));

处理错误

Fetch API 提供了一个清晰的方式来处理请求和响应中的错误。通过链式的 catch 方法,可以捕获和处理任何在请求过程中发生的错误。

typescript 复制代码
fetch('https://www.Feng.com/data')
  .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('There was a problem with the fetch operation:', error));

跨域请求

Fetch API 遵循同源策略,但可以通过服务器配置 CORS 来允许跨域请求。

typescript 复制代码
fetch('https://www.Feng.com/data', {
  method: 'GET',
  mode: 'cors', // 请求模式,默认是 'cors'
  headers: {
    'Content-Type': 'application/json'
  }
})
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error('Error:', error));

2.4 示例代码

以下是一个完整的示例代码,展示了如何使用 Fetch API 来执行各种网络请求,并处理响应数据。

HTML:

xml 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Fetch API Example</title>
</head>
<body>
  <button id="getButton">GET Data</button>
  <button id="postButton">POST Data</button>
  <pre id="output"></pre>
  <script src="fetch.js"></script>
</body>
</html>

JavaScript:

typescript 复制代码
const getButton = document.getElementById('getButton');
const postButton = document.getElementById('postButton');
const output = document.getElementById('output');

getButton.addEventListener('click', () => {
  fetch('https://www.Feng.com/data')
    .then(response => {
      if (!response.ok) {
        throw new Error('Network response was not ok');
      }
      return response.json();
    })
    .then(data => {
      output.textContent = JSON.stringify(data, null, 2);
    })
    .catch(error => {
      console.error('There was a problem with the fetch operation:', error);
    });
});

postButton.addEventListener('click', () => {
  fetch('https://www.Feng.com/data', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({ name: 'Feng', age: 26 })
  })
  .then(response => {
    if (!response.ok) {
      throw new Error('Network response was not ok');
    }
    return response.json();
  })
  .then(data => {
    output.textContent = JSON.stringify(data, null, 2);
  })
  .catch(error => {
    console.error('There was a problem with the fetch operation:', error);
  });
});

2.5 安全性

Fetch API 提供了多种机制来确保请求和响应的安全性:

  1. CORS:通过服务器配置 CORS 头,允许跨域请求,同时保护服务器免受未授权的访问。
  2. HTTPS:始终使用 HTTPS 协议来加密请求和响应数据,防止中间人攻击。
  3. 请求验证:在请求头中包含授权信息,如 JWT(JSON Web Token)或 API 密钥,确保请求的合法性。

2.6 使用场景

Fetch API 广泛应用于以下场景:

  1. 数据获取和提交:如获取用户数据、提交表单等。
  2. 文件上传和下载:如上传图片、下载文件等。
  3. 流媒体处理:如处理视频流、音频流等。
  4. 与第三方 API 交互:如与社交媒体 API、支付网关 API 等进行交互。

3. Axios

Axios 是一个基于 Promise 的 HTTP 客户端,用于浏览器和 Node.js。它提供了一个简洁、灵活且强大的 API,用于发出 HTTP 请求并处理响应。由于其广泛的功能和易用性,Axios 在前端开发中得到了广泛应用。

这个小伙伴们太熟悉了,这是目前国内最流行的请求库了。

3.1 Axios 的优点

  1. 基于 Promise:Axios 使用 Promise,使异步代码更加简洁和易于理解。
  2. 支持浏览器和 Node.js:Axios 既可以在浏览器环境中使用,也可以在 Node.js 环境中使用,具有很好的跨平台特性。
  3. 自动转换 JSON 数据:Axios 会自动将请求和响应中的 JSON 数据进行转换,简化了数据处理。
  4. 支持拦截器:Axios 提供了请求和响应拦截器,允许在请求或响应被处理前对其进行修改。
  5. 取消请求:Axios 支持取消请求,方便在需要时终止未完成的请求。
  6. 并发请求:Axios 提供了处理并发请求的简便方法。

Promise这个概念很重要,很多小伙伴都会使用Promise,还是建议大家尽量深入了解下,会发现Promise里面有更加广阔的世界。

3.2 Axios 的缺点

  1. 依赖性:由于 Axios 是一个第三方库,使用它需要引入额外的依赖。

  2. 体积较大:相比原生的 Fetch API,Axios 的库文件较大,可能会增加项目的体积。

3.3 Axios 的用法

Axios 的基本用法涉及创建一个网络请求并处理响应。它返回一个 Promise,该 Promise 会在请求完成后解析为一个 Response 对象。

安装 Axios

可以通过 npm 或 yarn 安装 Axios,也可以直接在 HTML 中引入 CDN 链接。

npm install axios

csharp 复制代码
yarn add axios

在 HTML 中引入:

xml 复制代码
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>

基本用法

ini 复制代码
axios.get('https://www.feng.com/data')
  .then(response => {
    console.log(response.data);
  })
  .catch(error => {
    console.error('Error:', error);
  });

创建请求

Axios 可以使用多种方法来创建请求,包括 get、post、put、delete 等。

typescript 复制代码
// GET 请求
axios.get('https://www.feng.com/data')
  .then(response => console.log(response.data))
  .catch(error => console.error('Error:', error));

// POST 请求
axios.post('https://www.feng.com/data', {
    name: 'Feng',
    age: 26
  })
  .then(response => console.log(response.data))
  .catch(error => console.error('Error:', error));

// PUT 请求
axios.put('https://www.feng.com/data/1', {
    name: 'Feng',
    age: 26
  })
  .then(response => console.log(response.data))
  .catch(error => console.error('Error:', error));

// DELETE 请求
axios.delete('https://www.feng.com/data/1')
  .then(response => console.log(response.data))
  .catch(error => console.error('Error:', error));

设置请求头

可以通过配置对象的 headers 属性来设置请求头。常用的请求头包括 Content-Type、Authorization 等。

typescript 复制代码
axios.post('https://www.feng.com/data', {
    name: 'Feng',
    age: 26
  }, {
    headers: {
      'Content-Type': 'application/json',
      'Authorization': 'Bearer token'
    }
  })
  .then(response => console.log(response.data))
  .catch(error => console.error('Error:', error));

处理响应

Axios 的响应对象包含多个属性,如 data、status、statusText、headers 等,方便我们处理响应数据。

lua 复制代码
axios.get('https://www.feng.com/data')
  .then(response => {
    console.log('Data:', response.data);
    console.log('Status:', response.status);
    console.log('Status Text:', response.statusText);
    console.log('Headers:', response.headers);
  })
  .catch(error => {
    console.error('Error:', error);
  });

处理错误

Axios 提供了一个清晰的方式来处理请求和响应中的错误。通过 catch 方法,可以捕获和处理任何在请求过程中发生的错误。

typescript 复制代码
axios.get('https://www.feng.com/data')
  .then(response => console.log(response.data))
  .catch(error => {
    if (error.response) {
      // 请求已发出,但服务器响应状态码不在 2xx 范围内
      console.error('Error Response Data:', error.response.data);
      console.error('Error Response Status:', error.response.status);
      console.error('Error Response Headers:', error.response.headers);
    } else if (error.request) {
      // 请求已发出但没有收到响应
      console.error('Error Request:', error.request);
    } else {
      // 其他错误
      console.error('Error Message:', error.message);
    }
    console.error('Error Config:', error.config);
  });

并发请求

Axios 提供了 axios.all 和 axios.spread 方法来处理并发请求。

typescript 复制代码
axios.all([
  axios.get('https://www.feng.com/data1'),
  axios.get('https://www.feng.com/data2')
])
.then(axios.spread((response1, response2) => {
  console.log('Response 1:', response1.data);
  console.log('Response 2:', response2.data);
}))
.catch(error => {
  console.error('Error:', error);
});

取消请求

Axios 支持取消请求,这对于在需要时终止未完成的请求非常有用。可以使用 CancelToken 来实现。

ini 复制代码
const CancelToken = axios.CancelToken;
const source = CancelToken.source();

axios.get('https://www.feng.com/data', {
  cancelToken: source.token
})
.then(response => console.log(response.data))
.catch(error => {
  if (axios.isCancel(error)) {
    console.log('Request canceled', error.message);
  } else {
    console.error('Error:', error);
  }
});

// 取消请求
source.cancel('Operation canceled by the user.');

请求拦截器和响应拦截器

Axios 提供了请求拦截器和响应拦截器,允许在请求或响应被处理前对其进行修改。

javascript 复制代码
// 添加请求拦截器
axios.interceptors.request.use(config => {
  // 在发送请求之前做些什么
  console.log('Request Interceptor:', config);
  return config;
}, error => {
  // 处理请求错误
  return Promise.reject(error);
});

// 添加响应拦截器
axios.interceptors.response.use(response => {
  // 对响应数据做些什么
  console.log('Response Interceptor:', response);
  return response;
}, error => {
  // 处理响应错误
  return Promise.reject(error);
});

示例代码

以下是一个完整的示例代码,展示了如何使用 Axios 来执行各种网络请求,并处理响应数据。

HTML:

xml 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Axios Example</title>
</head>
<body>
  <button id="getButton">GET Data</button>
  <button id="postButton">POST Data</button>
  <pre id="output"></pre>
  <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
  <script src="axios.js"></script>
</body>
</html>

JavaScript:

ini 复制代码
const getButton = document.getElementById('getButton');
const postButton = document.getElementById('postButton');
const output = document.getElementById('output');

getButton.addEventListener('click', () => {
  axios.get('https://www.feng.com/data')
    .then(response => {
      output.textContent = JSON.stringify(response.data, null, 2);
    })
    .catch(error => {
      console.error('Error:', error);
    });
});

postButton.addEventListener('click', () => {
  axios.post('https://www.feng.com/data', {
      name: 'Feng',
      age: 26
    })
    .then(response => {
      output.textContent = JSON.stringify(response.data, null, 2);
    })
    .catch(error => {
      console.error('Error:', error);
    });
});

3.4 安全性

Axios 提供了多种机制来确保请求和响应的安全性:

  1. CORS:通过服务器配置 CORS 头,允许跨域请求,同时保护服务器免受未授权的访问。
  2. HTTPS:始终使用 HTTPS 协议来加密请求和响应数据,防止中间人攻击。
  3. 请求验证:在请求头中添加授权信息,如 JWT 或 API 密钥,以验证请求的合法性。
  4. 处理错误:始终处理错误响应,防止潜在的安全漏洞和信息泄露。

4. jQuery.ajax

jQuery.ajax 是 jQuery 库中用于执行异步 HTTP 请求的强大方法。它提供了一种简单而灵活的方式来与服务器进行通信,支持多种请求类型、数据格式和配置选项。

其实呢,jQuery.ajax本质也是对XMLHttpRequest对象的封装,jQuery的ajax方法极大的简化了执行Ajax请求的这个过程。
Axios也是对XMLHttpRequest对象的封装,只不过Axios是现代化封装。

4.1 jQuery.ajax 的优点

  1. 简单易用jQuery.ajax 提供了一个简洁的 API,使得执行 HTTP 请求变得非常简单。

  2. 兼容性好jQuery.ajax 具有良好的浏览器兼容性,支持几乎所有主流浏览器。

  3. 丰富的功能jQuery.ajax 提供了多种选项和回调函数,允许对请求进行详细配置和处理。

  4. 内置错误处理jQuery.ajax 提供了多种错误处理机制,便于开发者应对各种异常情况。

  5. 与 jQuery 其他功能集成jQuery.ajax 与 jQuery 的其他功能无缝集成,如 DOM 操作和事件处理。

4.2 jQuery.ajax 的缺点

  1. 依赖 jQuery 库 :使用 jQuery.ajax 需要引入 jQuery 库,这可能增加项目的体积。

  2. 相对较重:与原生的 Fetch API 相比,jQuery 的体积较大,可能会影响性能。

  3. 过时技术:随着原生 Fetch API 和其他现代技术的普及,jQuery.ajax 的使用逐渐减少。

4.3 jQuery.ajax 的用法

jQuery.ajax 的基本用法涉及创建一个网络请求并处理响应。它返回一个 jqXHR 对象,该对象实现了 Promise 接口,可以通过 donefailalways 方法处理响应。

引入 jQuery

在使用 jQuery.ajax 之前,需要引入 jQuery 库。可以通过 CDN 引入:

xml 复制代码
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>

基本用法

lua 复制代码
$.ajax({
  url: 'https://www.feng.com/data',
  method: 'GET',
  success: function(data) {
    console.log(data);
  },
  error: function(error) {
    console.error('Error:', error);
  }
});

创建请求

jQuery.ajax 可以使用多种方法来创建请求,包括 GETPOSTPUTDELETE 等。

javascript 复制代码
// GET 请求
$.ajax({
  url: 'https://www.feng.com/data',
  method: 'GET',
  success: function(data) {
    console.log(data);
  },
  error: function(error) {
    console.error('Error:', error);
  }
});

// POST 请求
$.ajax({
  url: 'https://www.feng.com/data',
  method: 'POST',
  data: JSON.stringify({ name: 'Feng', age: 26 }),
  contentType: 'application/json',
  success: function(data) {
    console.log(data);
  },
  error: function(error) {
    console.error('Error:', error);
  }
});

// PUT 请求
$.ajax({
  url: 'https://www.feng.com/data/1',
  method: 'PUT',
  data: JSON.stringify({ name: 'Feng', age: 26 }),
  contentType: 'application/json',
  success: function(data) {
    console.log(data);
  },
  error: function(error) {
    console.error('Error:', error);
  }
});

// DELETE 请求
$.ajax({
  url: 'https://www.feng.com/data/1',
  method: 'DELETE',
  success: function(data) {
    console.log(data);
  },
  error: function(error) {
    console.error('Error:', error);
  }
});

设置请求头

可以通过配置对象的 headers 属性来设置请求头。常用的请求头包括 Content-TypeAuthorization 等。

php 复制代码
$.ajax({
  url: 'https://www.feng.com/data',
  method: 'POST',
  data: JSON.stringify({ name: 'Feng', age: 26 }),
  contentType: 'application/json',
  headers: {
    'Authorization': 'Bearer token'
  },
  success: function(data) {
    console.log(data);
  },
  error: function(error) {
    console.error('Error:', error);
  }
});

处理响应

jQuery.ajax 的响应对象包含多个属性,如 responseTextstatusstatusText 等,方便我们处理响应数据。

lua 复制代码
$.ajax({
  url: 'https://www.feng.com/data',
  method: 'GET',
  success: function(data, textStatus, jqXHR) {
    console.log('Data:', data);
    console.log('Status:', jqXHR.status);
    console.log('Status Text:', jqXHR.statusText);
  },
  error: function(jqXHR, textStatus, errorThrown) {
    console.error('Error:', errorThrown);
  }
});

处理错误

jQuery.ajax 提供了一个清晰的方式来处理请求和响应中的错误。通过 error 回调函数,可以捕获和处理任何在请求过程中发生的错误。

javascript 复制代码
$.ajax({
  url: 'https://www.feng.com/data',
  method: 'GET',
  success: function(data) {
    console.log(data);
  },
  error: function(jqXHR, textStatus, errorThrown) {
    console.error('Error:', errorThrown);
    if (jqXHR.responseJSON) {
      console.error('Response JSON:', jqXHR.responseJSON);
    }
  }
});

并发请求

jQuery 提供了 $.when 方法来处理并发请求。

javascript 复制代码
$.when(
  $.ajax({ url: 'https://www.feng.com/data1', method: 'GET' }),
  $.ajax({ url: 'https://www.feng.com/data2', method: 'GET' })
).done(function(response1, response2) {
  console.log('Response 1:', response1[0]);
  console.log('Response 2:', response2[0]);
}).fail(function(jqXHR, textStatus, errorThrown) {
  console.error('Error:', errorThrown);
});

取消请求

尽管 jQuery.ajax 不像 Axios 那样提供内置的取消请求功能,但我们可以通过 jqXHR 对象的 abort 方法来实现。

javascript 复制代码
const request = $.ajax({
  url: 'https://www.feng.com/data',
  method: 'GET'
});

request.done(function(data) {
  console.log(data);
});

request.fail(function(jqXHR, textStatus, errorThrown) {
  console.error('Error:', errorThrown);
});

// 取消请求
request.abort();

请求拦截器

虽然 jQuery 不直接提供请求拦截器,但我们可以通过扩展 $.ajaxSetup 方法来实现类似的功能。

javascript 复制代码
$.ajaxSetup({
  beforeSend: function(jqXHR, settings) {
    console.log('Request Interceptor:', settings);
  },
  complete: function(jqXHR, textStatus) {
    console.log('Response Interceptor:', textStatus);
  }
});

$.ajax({
  url: 'https://www.feng.com/data',
  method: 'GET',
  success: function(data) {
    console.log(data);
  },
  error: function(error) {
    console.error('Error:', error);
  }
});

4.4 示例代码

以下是一个完整的示例代码,展示了如何使用 jQuery.ajax 来执行各种网络请求,并处理响应数据。

HTML:


xml 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>jQuery.ajax Example</title>
</head>
<body>
  <button id="getButton">GET Data</button>
  <button id="postButton">POST Data</button>
  <pre id="output"></pre>
  <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
  <script src="jquery-ajax.js"></script>
</body>
</html>

JavaScript:

javascript 复制代码
const getButton = document.getElementById('getButton');
const postButton = document.getElementById('postButton');
const output = document.getElementById('output');

getButton.addEventListener('click', () => {
  $.ajax({
    url: 'https://www.feng.com/data',
    method: 'GET',
    success: function(data) {
      output.textContent = JSON.stringify(data, null, 2);
    },
    error: function(error) {
      console.error('Error:', error);
    }
  });
});

postButton.addEventListener('click', () => {
  $.ajax({
    url: 'https://www.feng.com/data',
    method: 'POST',
    data: JSON.stringify({ name: 'Feng', age: 26 }),
    contentType: 'application/json',
    success: function(data) {
      output.textContent = JSON.stringify(data, null, 2);
    },
    error: function(error) {
      console.error('Error:', error);
    }
  });
});

4.5 安全性

  1. 验证输入数据:在发送请求之前,验证用户输入的数据,防止 XSS 和注入攻击。
  2. 使用 HTTPS:确保所有请求使用 HTTPS 协议,防止中间人攻击。
  3. 授权和身份验证:在请求头中添加授权信息,如 JWT 或 API 密钥,以验证请求的合法性。
  4. 处理错误:始终处理错误响应,防止潜在的安全漏洞和信息泄露。

5. Beacon API

Beacon API 是一种专门用于从网页向服务器发送小量数据的 API,主要用于统计和诊断信息的传递。它在页面卸载(如页面关闭或导航到新页面)时特别有用,因为它能够确保数据在页面卸载前成功发送到服务器。

5.1 Beacon API 的优点

  • 可靠性高:在页面卸载时,能够保证数据发送成功。

  • 简洁易用:API 简单易用,只需调用一个方法即可发送数据。

  • 非阻塞:不会阻塞页面的卸载操作,提升用户体验。

  • 适用于传输小量数据:特别适合发送统计和诊断信息等小量数据。

5.2 Beacon API 的缺点

  • 只适用于小量数据:不适合传输大文件或大量数据。

  • 不支持自定义请求头:无法自定义请求头,限制了某些高级用法。

  • 有限的错误处理:无法直接获取发送失败的反馈。

5.3 Beacon API 的用法

1. 基本用法

使用 navigator.sendBeacon 方法发送数据。它接受两个参数:目标 URL 和要发送的数据。

ini 复制代码
const url = 'https://www.example.com/log';
const data = JSON.stringify({ event: 'pageUnload', timestamp: Date.now() });
navigator.sendBeacon(url, data);

2. 发送数据类型

sendBeacon 方法支持发送多种类型的数据,包括字符串、Blob、ArrayBuffer 等。

  • 发送字符串数据:
ini 复制代码
const data = 'event=pageUnload&timestamp=' + Date.now();
navigator.sendBeacon(url, data);
  • 发送 Blob 数据:
ini 复制代码
const blob = new Blob(['event=pageUnload&timestamp=' + Date.now()], { type: 'application/x-www-form-urlencoded' });
navigator.sendBeacon(url, blob);
  • 发送 ArrayBuffer 数据:
ini 复制代码
const buffer = new ArrayBuffer(16);
const view = new DataView(buffer);
view.setUint32(0, Date.now());
navigator.sendBeacon(url, buffer);

5.4 使用场景

Beacon API 主要用于以下场景:

  • 用户行为分析:发送用户点击、页面浏览等行为数据。

  • 性能监控:发送页面加载时间、资源加载时间等性能数据。

  • 错误报告:发送 JavaScript 错误、网络错误等错误信息。

  • 应用诊断:发送应用状态、日志信息等诊断数据。

5.5 兼容性

Beacon API 支持的浏览器包括 Chrome、Firefox、Edge、Safari 等,但不支持 Internet Explorer。建议在使用前检查浏览器兼容性。

5.6 发送数据示例

以下是一些使用 Beacon API 发送数据的示例代码:

  • 发送用户行为数据
ini 复制代码
window.addEventListener('beforeunload', function() {
    const url = 'https://www.example.com/log';
    const data = JSON.stringify({ event: 'pageUnload', timestamp: Date.now() });
    navigator.sendBeacon(url, data);
});
  • 发送性能监控数据
javascript 复制代码
window.addEventListener('beforeunload', function() {
    const url = 'https://www.example.com/performance';
    const data = JSON.stringify({
        loadTime: window.performance.timing.loadEventEnd - window.performance.timing.navigationStart,
        resources: window.performance.getEntriesByType('resource')
    });
    navigator.sendBeacon(url, data);
});
  • 发送错误报告
vbnet 复制代码
window.addEventListener('error', function(event) {
    const url = 'https://www.example.com/error';
    const data = JSON.stringify({
        message: event.message,
        source: event.filename,
        line: event.lineno,
        col: event.colno,
        error: event.error
    });
    navigator.sendBeacon(url, data);
});
  • 发送应用诊断数据
ini 复制代码
window.addEventListener('beforeunload', function() {
    const url = 'https://www.example.com/diagnostics';
    const data = JSON.stringify({
        state: app.getState(),
        logs: app.getLogs()
    });
    navigator.sendBeacon(url, data);
});

5.7 数据传输的可靠性

Beacon API 通过使用 HTTP POST 方法,将数据以非阻塞的方式传输到服务器。它使用浏览器的传输队列来确保数据在页面卸载前发送成功。即使页面已经关闭,浏览器仍会尝试发送数据。

5.8 数据接收与处理

服务器端需要处理接收到的 Beacon 数据。以下是一个简单的服务器端处理示例(使用 Node.js 和 Express):

javascript 复制代码
const express = require('express');
const app = express();
app.use(express.json());

app.post('/log', (req, res) => {
    console.log('Received log:', req.body);
    res.sendStatus(200);
});

app.post('/performance', (req, res) => {
    console.log('Received performance data:', req.body);
    res.sendStatus(200);
});

app.post('/error', (req, res) => {
    console.log('Received error report:', req.body);
    res.sendStatus(200);
});

app.post('/diagnostics', (req, res) => {
    console.log('Received diagnostics data:', req.body);
    res.sendStatus(200);
});

app.listen(3000, () => {
    console.log('Server is listening on port 3000');
});

5.9 使用最佳实践

  • 最小化数据量:尽量减少发送的数据量,以确保数据在页面卸载前能够发送成功。

  • 避免敏感信息:由于 Beacon API 无法自定义请求头,发送的数据不应包含敏感信息。

  • 多次发送:对于重要数据,可以在页面生命周期中多次发送,以提高数据传输的可靠性。

  • 合理使用 Blob:对于二进制数据,可以使用 Blob 对象进行传输。

6. WebSocket API

WebSocket API 是一种在单个 TCP 连接上进行全双工通信的协议,允许客户端和服务器之间实时数据交换。与传统的 HTTP 请求-响应模型不同,WebSocket 提供了持续的双向连接,使得数据可以在客户端和服务器之间即时传输,非常适合实时应用如在线聊天、实时更新、在线游戏等。

这个我们也很熟悉了,比如面试经常会问的心跳机制。

6.1 WebSocket API 的优点

  • 实时通信:提供全双工通信,允许客户端和服务器之间实时传输数据。

  • 低延迟:比 HTTP 轮询具有更低的延迟,减少了通信的开销。

  • 效率高:在保持连接的情况下,可以持续发送和接收数据,无需每次都建立新的连接。

  • 支持二进制数据:除了文本数据,还支持二进制数据传输。

6.2 WebSocket API 的缺点

  • 连接维持:需要维持一个持久连接,可能会占用更多的服务器资源。

  • 复杂性:相比于 HTTP 请求,WebSocket 的实现和管理更为复杂。

  • 防火墙问题:一些防火墙和代理服务器可能会阻止 WebSocket 连接。

6.3 WebSocket API 的用法

1. 创建 WebSocket 对象

创建 WebSocket 对象是使用 WebSocket 的第一步。通过 new WebSocket(url) 可以创建一个新的 WebSocket 连接。

ini 复制代码
const socket = new WebSocket('ws://www.example.com/socketserver');

2. 连接事件处理

可以使用 onopen 事件处理程序来处理连接成功事件。

ini 复制代码
socket.onopen = function(event) {
    console.log('WebSocket is open now.');
};

3. 发送数据

使用 send 方法可以向服务器发送数据。数据可以是字符串或二进制数据(Blob、ArrayBuffer)。

arduino 复制代码
socket.send('Hello Server!');

4. 接收数据

使用 onmessage 事件处理程序来处理接收到的数据。

ini 复制代码
socket.onmessage = function(event) {
    console.log('Received data from server:', event.data);
};

5. 关闭连接

使用 close 方法可以关闭 WebSocket 连接。

go 复制代码
socket.close();

使用 onclose 事件处理程序来处理连接关闭事件。

ini 复制代码
socket.onclose = function(event) {
    console.log('WebSocket is closed now.');
};

6. 处理错误

使用 onerror 事件处理程序来处理连接错误。

ini 复制代码
socket.onerror = function(event) {
    console.error('WebSocket error observed:', event);
};

6.4 WebSocket 连接管理

1. 自动重连

在实际应用中,WebSocket 连接可能会因为各种原因断开。为了提高应用的可靠性,可以实现自动重连机制。

ini 复制代码
function createWebSocket(url) {
    let socket = new WebSocket(url);

    socket.onopen = function(event) {
        console.log('WebSocket is open now.');
    };

    socket.onmessage = function(event) {
        console.log('Received data from server:', event.data);
    };

    socket.onclose = function(event) {
        console.log('WebSocket is closed now. Reconnecting...');
        setTimeout(function() {
            createWebSocket(url);
        }, 1000);
    };

    socket.onerror = function(event) {
        console.error('WebSocket error observed:', event);
    };

    return socket;
}

const socket = createWebSocket('ws://www.example.com/socketserver');

2. 心跳机制

为了保持 WebSocket 连接的活跃,可以实现心跳机制,定期发送心跳消息到服务器。

scss 复制代码
let socket;
let heartBeatInterval;

function startHeartBeat() {
    heartBeatInterval = setInterval(function() {
        if (socket.readyState === WebSocket.OPEN) {
            socket.send('ping');
        }
    }, 30000); // 每 30 秒发送一次心跳消息
}

function stopHeartBeat() {
    clearInterval(heartBeatInterval);
}

socket.onopen = function(event) {
    console.log('WebSocket is open now.');
    startHeartBeat();
};

socket.onclose = function(event) {
    console.log('WebSocket is closed now.');
    stopHeartBeat();
};

6.5 WebSocket 数据传输

1. 发送文本数据

WebSocket 允许发送文本数据,例如 JSON 字符串。

ini 复制代码
const message = JSON.stringify({ type: 'greeting', content: 'Hello Server!' });
socket.send(message);

2. 发送二进制数据

WebSocket 也支持发送二进制数据,例如 ArrayBuffer 和 Blob。

  • 发送 ArrayBuffer 数据:
ini 复制代码
const buffer = new ArrayBuffer(8);
const view = new Uint8Array(buffer);
view[0] = 0;
view[1] = 1;
view[2] = 2;
socket.send(buffer);
  • 发送 Blob 数据:
ini 复制代码
const blob = new Blob(['Hello, WebSocket!'], { type: 'text/plain' });
socket.send(blob);

3. 接收文本数据

接收到的消息可以是文本数据。

ini 复制代码
socket.onmessage = function(event) {
    const data = event.data;
    console.log('Received data:', data);
};

4. 接收二进制数据

可以处理接收到的二进制数据。

ini 复制代码
socket.binaryType = 'arraybuffer';
socket.onmessage = function(event) {
    const arrayBuffer = event.data;
    console.log('Received ArrayBuffer:', arrayBuffer);
};

6.6 安全性

WebSocket 可以通过 wss:// 协议进行加密传输,类似于 HTTPS,确保数据传输的安全性。建议在传输敏感数据时使用 wss:// 协议。

6.7 使用场景

WebSocket 适用于以下场景:

  • 实时聊天:例如即时通讯应用、聊天室等。

  • 实时更新:例如股票行情、体育比分等实时更新的数据。

  • 在线游戏:例如多人在线游戏,实时传输游戏状态和操作。

  • 实时协作:例如多人协作编辑文档、代码等。

  • 物联网:例如传感器数据实时传输、设备控制等。

6.8 兼容性

WebSocket API 支持的大多数现代浏览器,包括 Chrome、Firefox、Edge、Safari 等,但需要确保服务器和客户端均支持 WebSocket 协议。

7. Server-Sent Events (SSE)

Server-Sent Events (SSE) 是一种服务器推送技术,使服务器能够主动向客户端发送更新,而不需要客户端发出请求。SSE 使用 HTTP 协议,通过一个持续打开的 HTTP 连接,服务器可以在其上不断发送数据更新到客户端。这种方式非常适合实时更新的应用场景,如新闻推送、股票行情、社交媒体更新等。

小伙伴们是不是想到了WebSocket和轮询,我认为SSE很多方面都比这两种方法强。

7.1 SSE 的优点

  • 简单实现:SSE 基于 HTTP 协议,使用起来非常简单,只需要服务器不断发送更新,客户端接收即可。

  • 低开销:相比于轮询或 WebSocket,SSE 的开销较低,适合单向数据流的应用。

  • 自动重连:SSE 支持自动重连机制,当连接断开时,浏览器会自动尝试重新连接。

  • 浏览器支持好:现代主流浏览器如 Chrome、Firefox、Safari 等都支持 SSE。

7.2 SSE 的缺点

  • 单向通信:SSE 仅支持服务器向客户端发送数据,不支持双向通信。如果需要双向通信,需要结合其他技术如 WebSocket。

  • 受限于浏览器:某些旧版浏览器不支持 SSE,例如 IE 浏览器不支持 SSE。

  • 连接数限制:每个浏览器对同一域名的并发连接数有限制,SSE 会占用一个连接。

7.3 SSE 的用法

1. 创建 EventSource 对象

创建 EventSource 对象是使用 SSE 的第一步。通过 new EventSource(url) 可以创建一个新的 SSE 连接。

ini 复制代码
const eventSource = new EventSource('http://www.example.com/events');

2. 处理事件

使用 onmessage 事件处理程序来处理服务器发送的消息。

ini 复制代码
eventSource.onmessage = function(event) {
    console.log('Received data from server:', event.data);
};

3. 自定义事件

服务器可以发送自定义事件,客户端可以使用 addEventListener 来监听这些事件。

javascript 复制代码
eventSource.addEventListener('customEvent', function(event) {
    console.log('Received custom event data:', event.data);
});

4. 处理连接打开和关闭

使用 onopenonerror 事件处理程序来处理连接打开和关闭事件。

ini 复制代码
eventSource.onopen = function(event) {
    console.log('Connection to server opened.');
};

eventSource.onerror = function(event) {
    if (event.eventPhase === EventSource.CLOSED) {
        console.log('Connection to server closed.');
    } else {
        console.error('Error occurred:', event);
    }
};

7.4 SSE 数据格式

SSE 的数据格式非常简单,服务器发送的数据格式如下:

kotlin 复制代码
data: This is a message\n\n

数据格式的详细说明:

  • data:发送的数据,可以多行。
  • event:自定义事件类型。
  • id:消息的唯一 ID。
  • retry:客户端重连的时间间隔(毫秒)。

示例:

vbnet 复制代码
data: This is a message\n\n
event: customEvent\ndata: Custom event data\n\n
id: 123\ndata: This is a message with an ID\n\n
retry: 5000\ndata: This is a message with retry interval\n\n

7.5 处理断开和重连

SSE 支持自动重连机制,客户端在连接断开后会自动尝试重新连接。服务器可以通过 Last-Event-ID 头部字段来处理客户端重连时的消息丢失问题。

服务器发送消息时可以附带消息 ID:

python 复制代码
id: 123\ndata: This is a message with an ID\n\n

客户端在重新连接时会发送 Last-Event-ID 头部字段,服务器可以根据此 ID 来确定从哪条消息开始发送。

7.6 SSE 的使用场景

  • 实时更新:如新闻推送、股票行情、体育比分等实时数据更新。

  • 通知系统:如邮件通知、系统消息通知等。

  • 社交媒体:如社交媒体动态更新、评论实时更新等。

  • 监控系统:如服务器监控、应用状态监控等。

7.7 SSE 与 WebSocket 对比

7.8 SSE 兼容性

SSE 支持的大多数现代浏览器,包括 Chrome、Firefox、Safari 等,但 IE 浏览器不支持 SSE。可以使用 polyfill 或者其他替代方案来实现 IE 的支持。

8. XMLHttpRequest Level 2

XMLHttpRequest Level 2 (XHR2) 是对原始 XMLHttpRequest API 的扩展,提供了一些新功能和改进,以满足现代 Web 开发的需求。它使开发者能够更方便地与服务器进行异步通信,处理文件上传,监控请求进度,并支持跨域请求 (CORS)。

8.1 XMLHttpRequest Level 2 的优点

  1. 跨域请求支持:通过 CORS,XHR2 可以跨域发送请求和接收响应。

  2. 文件上传支持:使用 FormData 对象,可以方便地上传文件。

  3. 进度事件:可以监控请求的进度,包括上传和下载。

  4. Blob 和 ArrayBuffer 支持:可以发送和接收二进制数据。

  5. 超时设置:可以设置请求的超时时间。

8.2 XMLHttpRequest Level 2 的缺点

  1. 复杂性增加:虽然功能更强大,但使用起来比原始的 XMLHttpRequest 更复杂。

  2. 浏览器兼容性问题:虽然现代浏览器都支持 XHR2,但某些旧版浏览器可能不完全支持。

  3. 安全性问题:跨域请求可能带来安全风险,需要服务器正确配置 CORS。

8.3 XMLHttpRequest Level 2 的用法

1. 创建 XMLHttpRequest 对象

这是使用 XMLHttpRequest 的第一步,通过 new XMLHttpRequest() 创建一个新的 XMLHttpRequest 对象。

ini 复制代码
const xhr = new XMLHttpRequest();

2. 初始化请求

使用 open 方法来初始化请求。它有三个主要参数:请求方法(GET, POST 等)、请求 URL,以及是否异步(布尔值)。

kotlin 复制代码
xhr.open('GET', 'https://example.com/data', true);

3. 设置请求头

使用 setRequestHeader 方法来设置请求头,这在发送 POST 请求或需要特定的请求头时特别有用。

arduino 复制代码
xhr.setRequestHeader('Content-Type', 'application/json');

4. 发送请求

使用 send 方法来发送请求。对于 GET 请求,可以不传递参数;对于 POST 请求,可以传递请求体数据。

ini 复制代码
xhr.send();

对于 POST 请求,传递请求体数据:

ini 复制代码
const data = JSON.stringify({ name: 'Feng', age:26 });
xhr.send(data);

5. 处理响应

使用 onreadystatechange 事件处理响应。每当 readyState 属性改变时,onreadystatechange 事件会被触发。可以通过检查 readyStatestatus 来确定请求的状态和结果。

ini 复制代码
xhr.onreadystatechange = function() {
    if (xhr.readyState === 4) { // 请求完成
        if (xhr.status === 200) { // 成功
            console.log(xhr.responseText);
        } else {
            console.error('Error:', xhr.statusText);
        }
    }
};

6. 进度事件

XHR2 引入了进度事件,可以用来监控请求的进度。这对于文件上传和下载特别有用。

ini 复制代码
xhr.upload.onprogress = function(event) {
    if (event.lengthComputable) {
        const percentComplete = (event.loaded / event.total) * 100;
        console.log(`Upload progress: ${percentComplete}%`);
    }
};

xhr.onprogress = function(event) {
    if (event.lengthComputable) {
        const percentComplete = (event.loaded / event.total) * 100;
        console.log(`Download progress: ${percentComplete}%`);
    }
};

7. 处理错误

可以在 onerror 事件处理程序中处理网络错误。

ini 复制代码
xhr.onerror = function() {
    console.error('Request failed');
};

8. 跨域请求

XHR2 支持跨域请求,但需要服务器正确配置 CORS。服务器需要返回允许跨域的头部:

makefile 复制代码
Access-Control-Allow-Origin: https://yourdomain.com
Access-Control-Allow-Methods: GET, POST
Access-Control-Allow-Headers: Content-Type

前端代码:

ini 复制代码
xhr.open('GET', 'https://example.com/data', true);
xhr.withCredentials = true; // 如果需要发送凭证
xhr.send();

9. 文件上传

使用 FormData 对象,可以方便地上传文件。

ini 复制代码
const formData = new FormData();
formData.append('file', fileInput.files[0]);

const xhr = new XMLHttpRequest();
xhr.open('POST', 'https://example.com/upload', true);

xhr.upload.onprogress = function(event) {
    if (event.lengthComputable) {
        const percentComplete = (event.loaded / event.total) * 100;
        console.log(`Upload progress: ${percentComplete}%`);
    }
};

xhr.send(formData);

10. Blob 和 ArrayBuffer 支持

XHR2 支持发送和接收二进制数据。

发送 Blob:

go 复制代码
const blob = new Blob(['Hello, world!'], { type: 'text/plain' });

const xhr = new XMLHttpRequest();
xhr.open('POST', 'https://example.com/upload', true);
xhr.send(blob);

接收 ArrayBuffer:

ini 复制代码
xhr.responseType = 'arraybuffer';

xhr.onload = function() {
    if (xhr.status === 200) {
        const arrayBuffer = xhr.response;
        console.log(arrayBuffer);
    }
};

xhr.open('GET', 'https://example.com/data', true);
xhr.send();

8.4 示例代码

以下是一些完整的示例代码,展示如何使用 XMLHttpRequest Level 2 的不同功能。

  • GET 请求示例
ini 复制代码
const xhr = new XMLHttpRequest();
xhr.open('GET', 'https://example.com/data', true);

xhr.onreadystatechange = function() {
    if (xhr.readyState === 4) {
        if (xhr.status === 200) {
            console.log(JSON.parse(xhr.responseText));
        } else {
            console.error('Error:', xhr.statusText);
        }
    }
};

xhr.send();
  • POST 请求示例
ini 复制代码
const xhr = new XMLHttpRequest();
xhr.open('POST', 'https://example.com/data', true);
xhr.setRequestHeader('Content-Type', 'application/json');

xhr.onreadystatechange = function() {
    if (xhr.readyState === 4) {
        if (xhr.status === 200) {
            console.log(JSON.parse(xhr.responseText));
        } else {
            console.error('Error:', xhr.statusText);
        }
    }
};

const data = JSON.stringify({ name: 'Feng', age: 26 });
xhr.send(data);
  • 文件上传示例
ini 复制代码
const formData = new FormData();
formData.append('file', fileInput.files[0]);

const xhr = new XMLHttpRequest();
xhr.open('POST', 'https://example.com/upload', true);

xhr.upload.onprogress = function(event) {
    if (event.lengthComputable) {
        const percentComplete = (event.loaded / event.total) * 100;
        console.log(`Upload progress: ${percentComplete}%`);
    }
};

xhr.send(formData);
  • Blob 发送示例
go 复制代码
const blob = new Blob(['Hello, world!'], { type: 'text/plain' });

const xhr = new XMLHttpRequest();
xhr.open('POST', 'https://example.com/upload', true);
xhr.send(blob);
  • ArrayBuffer 接收示例
ini 复制代码
const xhr = new XMLHttpRequest();
xhr.responseType = 'arraybuffer';

xhr.onload = function() {
    if (xhr.status === 200) {
        const arrayBuffer = xhr.response;
        console.log(arrayBuffer);
    }
};

xhr.open('GET', 'https://example.com/data', true);
xhr.send();

8.5 安全性

使用 XHR2 时,必须注意安全性问题,特别是跨域请求。确保服务器正确配置了 CORS 头,以防止跨站脚本攻击。此外,可以使用 Content Security Policy (CSP) 来限制脚本的来源,防止恶意代码的执行。

8.6 常见问题

  1. 请求被阻止:确保服务器正确配置了 CORS 头。
  2. 进度事件不触发:确保请求的 Content-Length 头已正确设置。
  3. Blob/ArrayBuffer 不支持 :检查浏览器的支持情况,并确保 responseType 设置正确。

9. WebRTC

WebRTC(Web Real-Time Communication)是一项由W3C(World Wide Web Consortium)和IETF(Internet Engineering Task Force)共同制定的技术标准,用于实现浏览器和移动应用之间的实时音视频通信以及数据共享。WebRTC 提供了简单、强大且可扩展的 API,使开发者能够在其应用中轻松集成实时通信功能。

9.1 WebRTC 的优点

  1. 实时通信:WebRTC 提供低延迟、高质量的音视频通信,适合实时应用,如视频会议、在线教育等。

  2. 点对点连接:WebRTC 通过直接的点对点连接,减少了服务器负载和通信延迟。

  3. 跨平台支持:WebRTC 支持在多个平台上运行,包括桌面浏览器、移动设备和嵌入式系统。

  4. 开源免费:WebRTC 是一个开源项目,开发者可以免费使用并进行修改。

  5. 安全性:WebRTC 使用了 SRTP(Secure Real-time Transport Protocol)和 DTLS(Datagram Transport Layer Security)来加密音视频流和数据通道,确保通信的安全性。

9.2 WebRTC 的缺点

  1. 复杂性增加:WebRTC 的 API 复杂且涉及多种协议,开发和调试需要一定的学习成本。

  2. 网络条件依赖:WebRTC 的性能和稳定性依赖于网络质量,不良的网络条件可能导致通信质量下降。

  3. 兼容性问题:虽然现代浏览器都支持 WebRTC,但某些旧版浏览器或特定环境可能不完全支持。

  4. NAT 和防火墙穿透:在一些网络环境下,实现 NAT(Network Address Translation)和防火墙穿透可能会遇到困难。

9.3 WebRTC 的用法

WebRTC 的基本组成部分包括三个核心 API:MediaStreamRTCPeerConnectionRTCDataChannel

1. MediaStream API

MediaStream API 用于获取和操作媒体流(音频和视频)。可以使用 getUserMedia 方法来访问用户的摄像头和麦克风。

ini 复制代码
navigator.mediaDevices.getUserMedia({ video: true, audio: true })
  .then(stream => {
    const videoElement = document.querySelector('video');
    videoElement.srcObject = stream;
  })
  .catch(error => {
    console.error('Error accessing media devices.', error);
  });

2. RTCPeerConnection API

RTCPeerConnection 是 WebRTC 的核心组件,用于建立和控制点对点连接。

创建 RTCPeerConnection
ini 复制代码
const configuration = {
  iceServers: [
    { urls: 'stun:stun.l.google.com:19302' }
  ]
};
const peerConnection = new RTCPeerConnection(configuration);
添加媒体流到连接
ini 复制代码
navigator.mediaDevices.getUserMedia({ video: true, audio: true })
  .then(stream => {
    stream.getTracks().forEach(track => peerConnection.addTrack(track, stream));
  })
  .catch(error => {
    console.error('Error accessing media devices.', error);
  });
处理 ICE 候选

ICE(Interactive Connectivity Establishment)候选是 WebRTC 用于寻找最佳路径以建立点对点连接的机制。

csharp 复制代码
peerConnection.onicecandidate = event => {
  if (event.candidate) {
    // 发送 ICE 候选到远端对等体
    sendCandidateToRemote(event.candidate);
  }
};
创建和交换 SDP

SDP(Session Description Protocol)是用于描述多媒体通信会话的格式。对等体之间需要交换 SDP 信息来建立连接。

创建 Offer
ini 复制代码
peerConnection.createOffer()
  .then(offer => {
    return peerConnection.setLocalDescription(offer);
  })
  .then(() => {
    // 发送 SDP Offer 到远端对等体
    sendOfferToRemote(peerConnection.localDescription);
  })
  .catch(error => {
    console.error('Error creating offer.', error);
  });
处理 Offer
typescript 复制代码
peerConnection.setRemoteDescription(new RTCSessionDescription(offer))
  .then(() => {
    return peerConnection.createAnswer();
  })
  .then(answer => {
    return peerConnection.setLocalDescription(answer);
  })
  .then(() => {
    // 发送 SDP Answer 到远端对等体
    sendAnswerToRemote(peerConnection.localDescription);
  })
  .catch(error => {
    console.error('Error handling offer.', error);
  });
处理 Answer
go 复制代码
peerConnection.setRemoteDescription(new RTCSessionDescription(answer))
  .catch(error => {
    console.error('Error setting remote description.', error);
  });

3. RTCDataChannel API

RTCDataChannel 提供了在对等体之间发送任意数据的功能。

创建 Data Channel
ini 复制代码
const dataChannel = peerConnection.createDataChannel('chat');

dataChannel.onopen = () => {
  console.log('Data channel is open');
};

dataChannel.onmessage = event => {
  console.log('Received message:', event.data);
};
接收 Data Channel
ini 复制代码
peerConnection.ondatachannel = event => {
  const dataChannel = event.channel;

  dataChannel.onopen = () => {
    console.log('Data channel is open');
  };

  dataChannel.onmessage = event => {
    console.log('Received message:', event.data);
  };
};

9.4 示例代码

以下是一个完整的示例代码,展示了如何使用 WebRTC API 来建立一个简单的音视频通信和数据通道。

HTML:

xml 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>WebRTC Example</title>
</head>
<body>
  <video id="localVideo" autoplay playsinline></video>
  <video id="remoteVideo" autoplay playsinline></video>
  <script src="webrtc.js"></script>
</body>
</html>

JavaScript:

javascript 复制代码
const localVideo = document.getElementById('localVideo');
const remoteVideo = document.getElementById('remoteVideo');

const configuration = {
  iceServers: [
    { urls: 'stun:stun.l.google.com:19302' }
  ]
};
const peerConnection = new RTCPeerConnection(configuration);

navigator.mediaDevices.getUserMedia({ video: true, audio: true })
  .then(stream => {
    localVideo.srcObject = stream;
    stream.getTracks().forEach(track => peerConnection.addTrack(track, stream));
  })
  .catch(error => {
    console.error('Error accessing media devices.', error);
  });

peerConnection.onicecandidate = event => {
  if (event.candidate) {
    sendCandidateToRemote(event.candidate);
  }
};

peerConnection.ontrack = event => {
  remoteVideo.srcObject = event.streams[0];
};

peerConnection.createOffer()
  .then(offer => {
    return peerConnection.setLocalDescription(offer);
  })
  .then(() => {
    sendOfferToRemote(peerConnection.localDescription);
  })
  .catch(error => {
    console.error('Error creating offer.', error);
  });

function handleRemoteOffer(offer) {
  peerConnection.setRemoteDescription(new RTCSessionDescription(offer))
    .then(() => {
      return peerConnection.createAnswer();
    })
    .then(answer => {
      return peerConnection.setLocalDescription(answer);
    })
    .then(() => {
      sendAnswerToRemote(peerConnection.localDescription);
    })
    .catch(error => {
      console.error('Error handling offer.', error);
    });
}

function handleRemoteAnswer(answer) {
  peerConnection.setRemoteDescription(new RTCSessionDescription(answer))
    .catch(error => {
      console.error('Error setting remote description.', error);
    });
}

function handleRemoteCandidate(candidate) {
  peerConnection.addIceCandidate(new RTCIceCandidate(candidate))
    .catch(error => {
      console.error('Error adding ICE candidate.', error);
    });
}

function sendOfferToRemote(offer) {
  // Implement this function to send the offer to the remote peer
}

function sendAnswerToRemote(answer) {
  // Implement this function to send the answer to the remote peer
}

function sendCandidateToRemote(candidate) {
  // Implement this function to send the candidate to the remote peer
}

9.5 安全性

WebRTC 使用多种安全协议来保护通信安全,包括:

  1. SRTP:用于加密音视频流,防止窃听和篡改。

  2. DTLS:用于加密数据通道和信令数据,确保数据完整性和保密性。

  3. 同源策略:WebRTC 遵循浏览器的同源策略,防止跨站脚本攻击。

9.6 使用场景

WebRTC 广泛应用于以下场景:

  1. 视频会议:如 Zoom、Google Meet 等。
  2. 在线教育:如实时教学、远程实验等。
  3. 远程医疗:如医生与患者之间的视频咨询。
  4. 社交媒体:如实时视频聊天和直播。
  5. 游戏:如实时多人游戏中的语音聊天和数据同步。

10. 对比

10.1 用途与类型

  • XMLHttpRequest 和 XMLHttpRequest Level 2: 早期的AJAX技术,用于从服务器异步获取数据。Level 2是XMLHttpRequest的扩展,增加了更多功能。

  • Fetch API: 现代、基于Promise的API,用于网络请求,支持跨域。

  • Axios: 基于Promise的HTTP客户端,用于浏览器和node.js,提供易于使用的API。

  • jQuery.ajax: jQuery库中的AJAX方法,封装了XMLHttpRequest,提供更简单的API。

  • Beacon API: 用于在不影响当前页面性能的情况下,发送数据到服务器。

  • WebSocket API: 提供全双工通信渠道,允许服务器与客户端之间的实时、双向通信。

  • Server-Sent Events (SSE): 允许服务器主动向客户端发送更新,基于HTTP协议,但只能单向通信。

  • WebRTC: 不是直接用于HTTP请求,而是用于浏览器之间的实时通信,支持视频、音频和数据共享。

10.2 同步性与实时性

  • XMLHttpRequest 和 XMLHttpRequest Level 2、Fetch API、Axios、jQuery.ajax: 异步操作,但非实时通信(除非通过轮询)。

  • Beacon API: 异步,设计用于不阻塞页面的数据发送。

  • WebSocket API 和 WebRTC: 提供实时双向通信。

  • SSE: 实时单向通信(从服务器到客户端)。

10.3 复杂度

  • XMLHttpRequest 和 XMLHttpRequest Level 2: 较为原始,需要处理较多细节。

  • Fetch API: 较为现代,使用Promise,但可能需要额外的库来处理复杂需求(如JSON解析)。

  • Axios: 封装良好,提供简洁的API,易于使用。

  • jQuery.ajax: 简化了XMLHttpRequest的使用,但依赖jQuery库。

  • Beacon API: 非常简单,用于发送少量数据。

  • WebSocket API、SSE、WebRTC: 复杂度较高,需要处理网络事件和可能的连接问题。

10.4 兼容性

  • XMLHttpRequest 和 XMLHttpRequest Level 2: 广泛支持,几乎所有现代浏览器都支持。

  • Fetch API: 现代浏览器支持,但在一些旧版浏览器中可能需要polyfill。

  • Axios: 作为JavaScript库,其兼容性取决于其使用的Promise API的兼容性。

  • jQuery.ajax: 依赖于jQuery库,jQuery的兼容性较好。

  • Beacon API、WebSocket API、SSE、WebRTC: 大多数现代浏览器支持,但在某些旧浏览器上可能不可用。

10.5 使用场景

  • XMLHttpRequest 和 XMLHttpRequest Level 2、Fetch API、Axios、jQuery.ajax: 适用于需要从服务器异步获取数据的情况。

  • Beacon API: 适用于发送分析数据、日志等,不影响页面性能。

  • WebSocket API: 实时游戏、聊天应用、实时通知等需要双向实时通信的场景。

  • SSE: 实时新闻更新、股票行情等需要从服务器实时获取数据但不需要发送数据的场景。

  • WebRTC: 视频会议、在线游戏等需要实时音视频通信的场景。

11. 总结

这九种请求方式都梳理完了,好像,貌似,对以后的项目帮助不大,但是学是学到了,以后用不用得到,以后再说吧。

相关推荐
神夜大侠1 小时前
VUE 实现公告无缝循环滚动
前端·javascript·vue.js
明辉光焱1 小时前
【Electron】Electron Forge如何支持Element plus?
前端·javascript·vue.js·electron·node.js
柯南二号1 小时前
HarmonyOS ArkTS 下拉列表组件
前端·javascript·数据库·harmonyos·arkts
wyy72931 小时前
v-html 富文本中图片使用element-ui image-viewer组件实现预览,并且阻止滚动条
前端·ui·html
前端郭德纲2 小时前
ES6的Iterator 和 for...of 循环
前端·ecmascript·es6
究极无敌暴龙战神X2 小时前
前端学习之ES6+
开发语言·javascript·ecmascript
王解2 小时前
【模块化大作战】Webpack如何搞定CommonJS与ES6混战(3)
前端·webpack·es6
欲游山河十万里2 小时前
(02)ES6教程——Map、Set、Reflect、Proxy、字符串、数值、对象、数组、函数
前端·ecmascript·es6
明辉光焱2 小时前
【ES6】ES6中,如何实现桥接模式?
前端·javascript·es6·桥接模式
PyAIGCMaster2 小时前
python环境中,敏感数据的存储与读取问题解决方案
服务器·前端·python