文章

Web实时通信的几种方式

在 Web 应用中,实时通信非常关键,无论是消息传递、通知还是数据更新。为了实现实时通信,通常使用 HTTP 轮询、服务器推送事件(SSE)、WebSocket 和 WebHooks 四种方法。本文将深入探讨它们的工作原理、适用场景及示例。

1. HTTP 轮询

工作原理:HTTP 轮询是一种最基础的通信方法,客户端定期向服务器发送请求,查询是否有新数据。即使没有更新,服务器也会响应,这种“问询”式的通信导致资源浪费。

优点:实现简单,对服务器和客户端要求较低,适合小型应用。

缺点:当请求频繁时,容易增加服务器负载;不适合数据更新较快的应用。

示例:假设有一个天气应用,用户每隔几分钟检查天气更新。由于不需要即时更新,应用可以采用 HTTP 轮询,每 5 分钟请求一次天气数据。

客户端(JavaScript)

1
2
3
4
5
6
7
8
9
function fetchUpdates() {
  fetch('/weather/updates')
    .then(response => response.json())
    .then(data => console.log('Updates:', data))
    .catch(error => console.error('Error:', error));
}

// 每 5 秒发送一次请求
setInterval(fetchUpdates, 5000);

服务器(Node.js/Express)

1
2
3
4
5
6
7
8
9
const express = require('express');
const app = express();

app.get('/weather/updates', (req, res) => {
  res.json({ update: 'New data available' });
});

app.listen(3000, () => console.log('Server running on port 3000'));

2. 服务器推送事件(SSE)

工作原理:SSE 允许服务器向客户端推送更新,客户端通过建立一次 HTTP 长连接,服务器即可连续向客户端发送数据。数据仅从服务器流向客户端(单向通信)。

优点:轻量级且高效,适合频繁但单向的数据更新。

缺点:仅支持从服务器到客户端的单向通信,不适用于需要双向互动的场景。

示例:比如新闻网站可以使用 SSE 将实时更新的新闻推送到用户浏览器。用户打开新闻页后,浏览器便可以持续接收到最新新闻,无需刷新页面。

客户端(JavaScript)

1
2
3
4
5
6
const eventSource = new EventSource('/stream');

eventSource.onmessage = (event) => {
  console.log('Update from server:', event.data);
};

服务器(Node.js/Express)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
const express = require('express');
const app = express();

app.get('/stream', (req, res) => {
  res.setHeader('Content-Type', 'text/event-stream');
  res.setHeader('Cache-Control', 'no-cache');
  res.setHeader('Connection', 'keep-alive');

  setInterval(() => {
    res.write(`data: ${JSON.stringify({ update: 'New data available' })}\n\n`);
  }, 5000);
});

app.listen(3000, () => console.log('Server running on port 3000'));

3. WebSocket

工作原理:WebSocket 允许双向通信。客户端与服务器建立连接后,双方可以实时发送和接收数据。这种方法适合需要快速响应的场景。

优点:双向通信、实时性高,适合高频互动的应用,如聊天、游戏。

缺点:需要建立和维护 WebSocket 连接,对服务器性能要求较高。

示例:即时聊天应用,如 Slack 或微信聊天。当用户发送消息时,服务器会即时传递给其他用户,确保所有人实时收到消息。

客户端(JavaScript)

1
2
3
4
5
6
7
8
9
10
const socket = new WebSocket('ws://localhost:3000');

socket.onopen = () => {
  console.log('WebSocket connection established');
  socket.send('Hello Server!');
};

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

服务器(Node.js/ws)

1
2
3
4
5
6
7
8
9
10
const WebSocket = require('ws');
const server = new WebSocket.Server({ port: 3000 });

server.on('connection', (socket) => {
  console.log('Client connected');
  socket.on('message', (message) => {
    console.log('Message from client:', message);
    socket.send(`Echo: ${message}`);
  });
});

4. WebHooks

工作原理:WebHooks 是一种服务器到服务器的通信方式,当一个服务器上的事件触发时,会自动向另一个服务器发送通知。例如,A 应用中的事件发生后,通知 B 应用执行特定任务。

优点:适合跨应用通知和自动化任务。

缺点:只能用于服务器间的事件触发,通常不直接面对终端用户。

示例:GitHub 提交代码后,触发 CI/CD 系统的构建过程。每次代码提交都会通过 WebHook 通知构建服务器启动编译和测试流程。

触发服务器(Node.js/Express),这里一般其实是配置到触发端,比如 GitHub / Azure DevOps 的 webhook

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
const express = require('express');
const app = express();
app.use(express.json());

app.post('/trigger-event', (req, res) => {
  fetch('http://another-server.com/webhook', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ event: 'Data Updated' })
  });
  res.send('Webhook triggered');
});

app.listen(3000, () => console.log('Server running on port 3000'));

接收服务器

1
2
3
4
5
6
7
8
9
10
const express = require('express');
const app = express();
app.use(express.json());

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

app.listen(4000, () => console.log('Server listening on port 4000'));

如何选择合适的技术

选择适合的实时通信方式时,需考虑数据更新频率、是否需要双向通信以及应用规模:

  • HTTP 轮询:简单且适合不频繁的数据更新;
  • SSE:当数据频繁更新且只需服务器向客户端发送时最适合;
  • WebSocket:用于实时双向通信,适合互动性强的应用;
  • WebHooks:适用于系统集成场景。

每种方式都有其使用的场景,需要结合具体需求进行选择,来优化应用性能和用户体验。

【全文完】

本文由作者按照 CC BY 4.0 进行授权