这篇文章详细介绍了前端的七种请求 API,包括 XMLHttpRequest 及 XMLHttpRequest Level 2、Fetch API、Beacon API、WebSocket API、Server-Sent Events (SSE)、WebRTC 等,分别阐述了它们的优点、缺点、用法、使用场景、安全性、兼容性等方面,并进行了对比

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

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

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

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

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

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

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

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

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

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

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

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

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

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 对象。

const xhr = new XMLHttpRequest();

1.4 初始化请求

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

xhr.open('GET', 'https://www.feng.com/data', true);

参数说明

method:

指定HTTP请求方法。

常用方法包括:

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

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

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

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

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

HTTP 请求方法

1.5 设置请求头

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

xhr.setRequestHeader('Content-Type', 'application/json');

常用的请求头包括 Content-Type(指定请求体的媒体类型)、Authorization(授权信息)等。

常见HTTP请求头

1.6 发送请求

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

xhr.send();

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

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

xhr.send(data);

1.7 处理响应

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

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 事件处理程序中检查状态码,并处理可能的错误。

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)头。示例如下:

xhr.open('GET', 'https://www.feng.com/data', true);

xhr.setRequestHeader('Origin', 'https://yourdomain.com');

xhr.send();

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

Access-Control-Allow-Origin: https://yourdomain.com

Access-Control-Allow-Methods: GET, POST

Access-Control-Allow-Headers: Content-Type

1.13 示例代码

GET 请求示例

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 请求示例

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 的优点

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

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

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

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

2.2 Fetch API 的缺点

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

有的小伙伴可能会想,是不是可以用async和await代替,但是呢,async和await并不会让fetch请求变成同步,只是会让请求看起来像是同步的,这里的异步是指会在异步环境中运行,并不会堵塞其他代码。

具体可以参考我的另一篇文章:juejin.cn/post/703921…

2.3 Fetch API 的用法

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

基本用法

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 和可选的配置对象。配置对象允许指定请求方法、请求头、请求体等。

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 等。以下是一些常见的请求方法及其示例。

// 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 等。

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() 等。

// 处理 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 方法,可以捕获和处理任何在请求过程中发生的错误。

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 来允许跨域请求。

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:

Fetch API Example

JavaScript:

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 提供了多种机制来确保请求和响应的安全性:

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

2.6 使用场景

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

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

3. Beacon API

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

3.1 Beacon API 的优点

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

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

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

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

3.2 Beacon API 的缺点

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

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

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

3.3 Beacon API 的用法

1. 基本用法

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

const url = 'https://www.example.com/log';

const data = JSON.stringify({ event: 'pageUnload', timestamp: Date.now() });

navigator.sendBeacon(url, data);

2. 发送数据类型

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

发送字符串数据:

const data = 'event=pageUnload×tamp=' + Date.now();

navigator.sendBeacon(url, data);

发送 Blob 数据:

const blob = new Blob(['event=pageUnload×tamp=' + Date.now()], { type: 'application/x-www-form-urlencoded' });

navigator.sendBeacon(url, blob);

发送 ArrayBuffer 数据:

const buffer = new ArrayBuffer(16);

const view = new DataView(buffer);

view.setUint32(0, Date.now());

navigator.sendBeacon(url, buffer);

3.4 使用场景

Beacon API 主要用于以下场景:

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

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

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

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

3.5 兼容性

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

3.6 发送数据示例

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

发送用户行为数据

window.addEventListener('beforeunload', function() {

const url = 'https://www.example.com/log';

const data = JSON.stringify({ event: 'pageUnload', timestamp: Date.now() });

navigator.sendBeacon(url, data);

});

发送性能监控数据

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);

});

发送错误报告

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);

});

发送应用诊断数据

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);

});

3.7 数据传输的可靠性

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

3.8 数据接收与处理

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

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');

});

3.9 使用最佳实践

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

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

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

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

4. WebSocket API

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

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

4.1 WebSocket API 的优点

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

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

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

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

4.2 WebSocket API 的缺点

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

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

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

4.3 WebSocket API 的用法

1. 创建 WebSocket 对象

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

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

2. 连接事件处理

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

socket.onopen = function(event) {

console.log('WebSocket is open now.');

};

3. 发送数据

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

socket.send('Hello Server!');

4. 接收数据

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

socket.onmessage = function(event) {

console.log('Received data from server:', event.data);

};

5. 关闭连接

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

socket.close();

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

socket.onclose = function(event) {

console.log('WebSocket is closed now.');

};

6. 处理错误

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

socket.onerror = function(event) {

console.error('WebSocket error observed:', event);

};

4.4 WebSocket 连接管理

1. 自动重连

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

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 连接的活跃,可以实现心跳机制,定期发送心跳消息到服务器。

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();

};

4.5 WebSocket 数据传输

1. 发送文本数据

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

const message = JSON.stringify({ type: 'greeting', content: 'Hello Server!' });

socket.send(message);

2. 发送二进制数据

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

发送 ArrayBuffer 数据:

const buffer = new ArrayBuffer(8);

const view = new Uint8Array(buffer);

view[0] = 0;

view[1] = 1;

view[2] = 2;

socket.send(buffer);

发送 Blob 数据:

const blob = new Blob(['Hello, WebSocket!'], { type: 'text/plain' });

socket.send(blob);

3. 接收文本数据

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

socket.onmessage = function(event) {

const data = event.data;

console.log('Received data:', data);

};

4. 接收二进制数据

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

socket.binaryType = 'arraybuffer';

socket.onmessage = function(event) {

const arrayBuffer = event.data;

console.log('Received ArrayBuffer:', arrayBuffer);

};

4.6 安全性

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

4.7 使用场景

WebSocket 适用于以下场景:

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

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

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

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

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

4.8 兼容性

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

5. Server-Sent Events (SSE)

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

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

5.1 SSE 的优点

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

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

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

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

5.2 SSE 的缺点

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

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

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

5.3 SSE 的用法

1. 创建 EventSource 对象

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

const eventSource = new EventSource('http://www.example.com/events');

2. 处理事件

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

eventSource.onmessage = function(event) {

console.log('Received data from server:', event.data);

};

3. 自定义事件

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

eventSource.addEventListener('customEvent', function(event) {

console.log('Received custom event data:', event.data);

});

4. 处理连接打开和关闭

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

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);

}

};

5.4 SSE 数据格式

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

data: This is a message\n\n

数据格式的详细说明:

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

示例:

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

5.5 处理断开和重连

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

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

id: 123\ndata: This is a message with an ID\n\n

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

5.6 SSE 的使用场景

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

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

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

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

5.7 SSE 与 WebSocket 对比

5.8 SSE 兼容性

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

6. XMLHttpRequest Level 2

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

6.1 XMLHttpRequest Level 2 的优点

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

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

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

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

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

6.2 XMLHttpRequest Level 2 的缺点

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

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

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

6.3 XMLHttpRequest Level 2 的用法

1. 创建 XMLHttpRequest 对象

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

const xhr = new XMLHttpRequest();

2. 初始化请求

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

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

3. 设置请求头

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

xhr.setRequestHeader('Content-Type', 'application/json');

4. 发送请求

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

xhr.send();

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

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

xhr.send(data);

5. 处理响应

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

xhr.onreadystatechange = function() {

if (xhr.readyState === 4) { // 请求完成

if (xhr.status === 200) { // 成功

console.log(xhr.responseText);

} else {

console.error('Error:', xhr.statusText);

}

}

};

6. 进度事件

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

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 事件处理程序中处理网络错误。

xhr.onerror = function() {

console.error('Request failed');

};

8. 跨域请求

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

Access-Control-Allow-Origin: https://yourdomain.com

Access-Control-Allow-Methods: GET, POST

Access-Control-Allow-Headers: Content-Type

前端代码:

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

xhr.withCredentials = true; // 如果需要发送凭证

xhr.send();

9. 文件上传

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

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:

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:

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();

6.4 示例代码

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

GET 请求示例

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 请求示例

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);

文件上传示例

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 发送示例

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 接收示例

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();

6.5 安全性

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

6.6 常见问题

请求被阻止:确保服务器正确配置了 CORS 头。

进度事件不触发:确保请求的 Content-Length 头已正确设置。

Blob/ArrayBuffer 不支持:检查浏览器的支持情况,并确保 responseType 设置正确。

7. WebRTC

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

7.1 WebRTC 的优点

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

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

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

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

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

7.2 WebRTC 的缺点

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

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

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

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

7.3 WebRTC 的用法

WebRTC 的基本组成部分包括三个核心 API:MediaStream、RTCPeerConnection 和 RTCDataChannel。

1. MediaStream API

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

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

const configuration = {

iceServers: [

{ urls: 'stun:stun.l.google.com:19302' }

]

};

const peerConnection = new RTCPeerConnection(configuration);

添加媒体流到连接

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 用于寻找最佳路径以建立点对点连接的机制。

peerConnection.onicecandidate = event => {

if (event.candidate) {

// 发送 ICE 候选到远端对等体

sendCandidateToRemote(event.candidate);

}

};

创建和交换 SDP

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

创建 Offer

peerConnection.createOffer()

.then(offer => {

return peerConnection.setLocalDescription(offer);

})

.then(() => {

// 发送 SDP Offer 到远端对等体

sendOfferToRemote(peerConnection.localDescription);

})

.catch(error => {

console.error('Error creating offer.', error);

});

处理 Offer

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

peerConnection.setRemoteDescription(new RTCSessionDescription(answer))

.catch(error => {

console.error('Error setting remote description.', error);

});

3. RTCDataChannel API

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

创建 Data Channel

const dataChannel = peerConnection.createDataChannel('chat');

dataChannel.onopen = () => {

console.log('Data channel is open');

};

dataChannel.onmessage = event => {

console.log('Received message:', event.data);

};

接收 Data Channel

peerConnection.ondatachannel = event => {

const dataChannel = event.channel;

dataChannel.onopen = () => {

console.log('Data channel is open');

};

dataChannel.onmessage = event => {

console.log('Received message:', event.data);

};

};

7.4 示例代码

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

HTML:

WebRTC Example

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

}

7.5 安全性

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

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

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

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

7.6 使用场景

WebRTC 广泛应用于以下场景:

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

8. 对比

8.1 用途与类型

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

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

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

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

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

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

8.2 同步性与实时性

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

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

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

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

8.3 复杂度

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

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

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

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

8.4 兼容性

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

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

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

8.5 使用场景

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

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

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

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

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

9. 总结

掌握这七种请求方法基本可以横着走了,就算一时记不住可以做个笔记。