实时更新:轮询、SSE 和 Web Sockets

在本文中,我们将介绍三种技巧/技术来实现实时更新功能:

  1. 轮询+长轮询
  2. SSE(服务器发送事件)
  3. Web Sockets

轮询

这是构建实时应用程序时最简单的方法。

在轮询中,客户端反复向服务器发出请求,希望获得更新/新的数据。不需要额外的步骤来实现这一点。只需将您的 API 调用包装起来即可setInterval。通俗地说,这就像每次几秒钟后刷新你的网页。

也许您会收到更新的数据,也可能不会。没有办法事先知道这一点。

javascript 复制代码
const URL = 'https://jsonplaceholder.typicode.com/posts/';

const fetchPosts = async () => {
  try {
    console.log('Fetching new data...');

    const response = await (await fetch(URL)).json();

    console.log('Data fetched!')

  } catch(err) {
    console.log('Request failed: ', err.message);
  }
}

setInterval(fetchPosts, 5000);

长轮询

既然我们正在讨论这个主题,那么值得在这里讨论一下长轮询。长轮询是轮询的天才/优化版本。

服务器不会立即发送响应,而是等待,直到为客户端提供一些新数据。客户渴望得到回应;这实际上很好,因为客户端没有被阻止并继续执行其他任务。据了解,这也需要在服务器端做出一些努力。

一旦客户端收到数据,它必须为下一个数据状态创建另一个请求。

javascript 复制代码
const URL = "https://jsonplaceholder.typicode.com/posts";

const fetchPosts = async () => {
  try {
    console.log("Fetching new data...");

    const response = await (await fetch(URL)).json();

    console.log("Data fetched!");

    return response;
  } catch (err) {
    console.log("Request failed: ", err.message);
  }
};

const longPoll = async () => {
  // response might be delayed as server might not have updated data
  const response = await fetchPosts();

  if (response) {
    return longPoll();
  }

}

longPoll();

注意: 这些片段提供了最低限度的内容,只是为了传达这个想法。您可能想为此添加更多功能,例如尝试计数或延迟。在代码中添加一些检查也是很好的,这样您就不会最终对自己的服务器进行 DOS 操作。

SSE 服务器发送事件

这是本文中我最喜欢的部分。在此之前,我只了解网络套接字并使用它们,即使对于小型应用程序也是如此。SSE 功能强大、简单,并且可以用最少的代码完成工作。

在SSE中,客户端向服务器发出初始请求以建立连接。发布服务器将更新的数据推送到客户端(只要有可用)。客户无需进一步参与。当然,客户端需要处理这些事件,但仅此而已。

javascript 复制代码
// server-side code in express

app.get("/real-time-updates", (req, res) => {
  res.setHeader("Content-Type", "text/event-stream");

  const sendRealTimeUpdates = () => {
    res.write("data: New data!\n\n");
    setTimeout(sendRealTimeUpdates, 3000);
  };

  sendRealTimeUpdates();
});

这是可能的最短实现。

  1. 我们创建了一条GET路线/real-time-updates
  2. Content-Type标题设置为text/event-stream.
  3. 用于res.write()向客户端发送数据。如果我们使用res.send()orres.end()它将关闭连接。

👉重要注意事项

  1. 该消息应始终以 开头data:
  2. 该消息应始终以 结尾\n\n

我们通过res.writesetTimeout.

ini 复制代码
// client-side code in vanilla JS

const URL = 'http://127.0.0.1:3000/real-time-updates';

const sseClient = new EventSource(URL);

sseClient.onopen = () => console.log('Connection opened!');

sseClient.onmessage = (event) => console.log(event.data);

sseClient.onerror = () => console.log('Something went wrong!');

我们使用EventSource接口与 SSE 端点建立连接。

  1. 使用 获取客户端实例EventSource。传递您要订阅的 URL。

  2. 我们得到 3 个事件处理程序,它们被称为不同的阶段。

    • onopen连接打开时调用。
    • onerror发生错误时被调用。
    • onmessage当我们从服务器接收到事件并且我们没有显式处理该事件时被调用。
  3. 我们还获得了一种close可用于随时关闭连接的方法。

如果我们不在服务器上指定事件类型,默认情况下,每个事件都具有类型message。因此,处理程序onmessage捕获每个事件。

但是,如果我们使用关键字指定事件,event:我们可以在客户端显式处理它。

swift 复制代码
// diff: server-side code with custom event

res.write("event: notification\ndata: New data!\n\n");
javascript 复制代码
// diff: client-side code with custom event handling

sseClient.addEventListener('notification', (event) => {
    console.log(event.data))
};

这就是添加您自己的 SSE 所需的全部代码。

⚠️当SSE通过HTTP/1.1实现时,它会受到最大连接数的限制;即 6。这意味着任何网站www.fake-dev.to最多可以在浏览器中打开 6 个 SSE 连接(包括多个选项卡)。建议使用 HTTP/2,默认限制为 100,但可以配置。

Web Sockets

Web Sockets 比上述方法更强大,但也带来了额外的复杂性。

Web Sockets 形成双工连接,这意味着客户端和服务器都可以在单个通道上相互发送数据,而 SSE 是单向的。

Web Sockets 由 HTTP 握手请求发起,但后来升级到 TCP 层。

HTTP 协议是无状态协议,这意味着所有标头(包括 cookie、令牌等)都会随每个请求一起发送。这使得它可以水平扩展。如果服务器 1 过载,请求可以由服务器 2 处理,并且由于我们在标头中拥有所有信息,因此没有什么区别。这也使得速度变慢,因为每个请求都需要发送更多数据。此外,一旦请求得到满足,连接就会关闭。因此,对于新请求,必须再次打开连接,这非常耗时。

另一方面,TCP 是有状态的。Web 套接字速度更快,因为连接保持活动状态以进行通信,并且每个请求都不会发送额外的标头。但这也使得扩展变得更加困难。如果客户端正在与服务器 1 通信,则所有请求应仅由服务器 1 处理。其他服务器不知道它的状态。

相关推荐
代码魔法师Sunny3 天前
4.WebSocket 配置与Nginx 的完美结合
websocket·网络协议
kunkun1013 天前
关于Websocket
网络·websocket·网络协议
flying robot4 天前
websocket的使用
websocket
azheng2225 天前
WebSocket消息帧的组成结构
websocket
._Ha!n.5 天前
WebSocket实现消息实时推送
网络·websocket·网络协议
蜀中孤鹰6 天前
由浅入深逐步理解spring boot中如何实现websocket
spring boot·后端·websocket
测试界的酸菜鱼6 天前
C# 如何处理 WebSocket 连接异常
开发语言·websocket·c#
布兰妮甜6 天前
WebSocket详解:从前端到后端的全栈理解
前端·websocket·网络协议
代码魔法师Sunny7 天前
2.WebSocket进阶: 深入探究实时通信的最佳实践与优化技巧
网络·websocket·网络协议
ઈ一笑ഒ7 天前
Django+websocket实现一个简单聊天
网络·websocket·网络协议