大数跨境

WebSocket 已过时?95%的实时应用,其实都该用 SSE

WebSocket 已过时?95%的实时应用,其实都该用 SSE 索引目录
2026-02-05
2
导读:关注「索引目录」公众号,获取更多干货。现在大家都默认使用 WebSocket 来实现实时功能。但大多数人不应该这样做。

关注「索引目录」公众号,获取更多干货。

现在大家都默认使用 WebSocket 来实现实时功能。但大多数人不应该这样做。

事实是: 95%的“实时”应用只需要服务器到客户端的更新。例如:聊天通知、实时仪表盘、股票行情、日志流、人工智能响应。

WebSocket 提供双向通信功能。但双向通信也带来一些弊端:复杂性、资源开销、扩展性挑战以及调试难题。

服务器发送事件 (SSE) 的功能只有一个:将数据从服务器流式传输到客户端。它们在这方面做得非常出色。对于大多数应用程序来说,这已经足够了。

以下是 SSE 应该成为实时功能默认选项的原因,并附有真实的生产数据和客观的权衡取舍。

WebSocket 假设

对话通常是这样的:

开发人员: “我们需要实时更新。”
团队: “使用 WebSocket。”
开发人员: “为什么?”
团队: “因为它们是实时的。”

没有人质疑这一点。WebSocket 已成为所有涉及“实时”或“动态”功能的默认选择。

但令人不安的事实是:双向沟通很少是必要的。

让我们来看看“实时”在生产应用中究竟意味着什么:

无需双向通信的实时功能:

仪表盘:

  • 服务器推送指标
  • 客户端渲染图表
  • 更新单向进行:服务器 → 客户端

通知:

  • 服务器发送警报
  • 客户展示它们
  • 单向

实时直播:

  • 服务器传输新内容(推文、帖子、事件)
  • 客户端向信息流添加内容
  • 单向

AI聊天(ChatGPT风格):

  • 服务器会在生成令牌时立即将其传输到服务器流中。
  • 客户逐字显示
  • 响应流程:服务器 → 客户端(用户输入通过单独的 POST 请求)

股票代码:

  • 服务器推送价格更新
  • 客户端更新界面
  • 单程

日志流:

  • 服务器尾部日志
  • 客户实时显示
  • 服务器 → 仅客户端

构建状态/CI/CD:

  • 服务器发送进度更新
  • 客户展示构建步骤
  • 单向

看出规律了吗?这些占了95%的“实时”用例。

真正需要双向通信的实时功能:

多人游戏:

  • 玩家发出走法
  • 服务器向所有玩家广播
  • 持续的双向交通

协作编辑(Google 文档):

  • 用户编辑文档
  • 服务器协调变更
  • 向所有编辑广播
  • 高频双向

视频通话/WebRTC信令:

  • 同伴发现
  • ICE候选人交换
  • 持续谈判

交易平台:

  • 用户下单
  • 服务器确认
  • 市场动态回流
  • 两个方向同时

WebSocket 在以下5% 的应用场景中表现出色。

至于其他功能呢?你实际上是在为那些你根本用不到的功能支付 WebSocket 税。

什么是服务器发送事件 (SSE)?

SSE 非常简单:它就是一个始终保持打开状态的 HTTP 连接。每当有新数据时,服务器都会向该连接写入数据。

协议:

GET /api/stream HTTP/1.1
Host: example.com
Accept: text/event-stream

HTTP/1.1 200 OK
Content-Type: text/event-stream
Cache-Control: no-cache

data: {"message": "Hello World"}

data: {"message": "Another update"}

data: {"message": "And another"}

就是这样。纯文本通过HTTP传输。无需协议升级。无需握手过程。

客户端代码(JavaScript):

const eventSource = new EventSource('/api/stream');

eventSource.onmessage = (event) => {
  const data = JSON.parse(event.data);
  console.log('Received:', data);
};

eventSource.onerror = (error) => {
  console.error('Connection error:', error);
  // Browser automatically reconnects
};

服务器端代码(Node.js/Fastify):

fastify.get('/api/stream', (req, reply) => {
  reply.raw.writeHead(200, {
    'Content-Type': 'text/event-stream',
    'Cache-Control': 'no-cache',
    'Connection': 'keep-alive'
  });

  const interval = setInterval(() => {
    const data = JSON.stringify({ message: 'Update', timestamp: Date.now() });
    reply.raw.write(`data: ${data}\n\n`);
  }, 1000);

  req.raw.on('close', () => {
    clearInterval(interval);
  });
});

10 行代码。无需任何库。仅支持 HTTP。

相比之下,WebSockets:

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

ws.onopen = () => {
  console.log('Connected');
  // Now what? Send ping? Subscribe to channels?
};

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

ws.onerror = (error) => {
  console.error('Error:', error);
  // Manual reconnection logic required
};

ws.onclose = () => {
  console.log('Connection closed');
  // Implement exponential backoff, reconnect...
};

// Send heartbeat to keep connection alive
setInterval(() => {
  if (ws.readyState === WebSocket.OPEN) {
    ws.send(JSON.stringify({ type: 'ping' }));
  }
}, 30000);

已经更复杂了。而且我们还没处理重连、消息排队或协议协商等问题。

SSE 与 WebSocket:真正的比较

让我们来看看实际部署的生产数据。

性能基准测试(Timeplus,2024)

测试设置:每秒 100,000 个事件,10-30 个并发连接

结果:


Metric
SSE
WebSocket
Difference
Max throughput
3M events/sec
3M events/sec
Tie
CPU usage (batch 50)
~42%
~40%
SSE +5%
Latency (50ms target)
48ms
45ms
WS -6%
Implementation complexity
10 lines
50+ lines
SSE 5x simpler


结论:性能基本相同。SSE 占用的 CPU 资源略多(可忽略不计),WebSocket 的延迟略低(相差 3 毫秒)。

对于每秒 10 万个事件来说,这种差异无关紧要。

资源利用率(生产,2025 年)

场景:实时仪表盘,10,000 个并发连接

上证综:

  • 内存:约20MB(仅连接状态)
  • CPU:空闲时 15%,负载时 35%
  • 网络:标准 HTTP
  • 缩放:水平(无状态,带背板)

WebSocket:

  • 内存:约50MB(连接缓冲区+帧缓冲区)
  • CPU:25% 空闲(ping/pong 帧),45% 负载下
  • 网络:持久 TCP + WebSocket 协议开销
  • 扩展性:需要粘性会话或消息背板

为什么会有这种差异?

SSE 就是 HTTP。没有帧掩码,没有协议协商,也没有 ping/pong 机制。

WebSocket 帧有开销:

[Frame Header (2-14 bytes)] [Payload]

每条消息都会被封装。客户端到服务器的消息会被屏蔽(异或运算会增加 CPU 开销)。

SSE 只写入文本:

data: {...}\n\n

无边框。无遮罩。极低的CPU占用率。

延迟深度解析

问:如果 WebSocket 速度快 3 毫秒,这重要吗?

答:几乎从不。

典型应用延迟预算:

User action: 0ms

Frontend validation: 5ms

Network RTT: 20-100ms (varies by location)

Backend processing: 10-500ms (depends on query)

Database query: 5-50ms

Response render: 10ms

Total: 50-665ms

SSE 和 WebSocket 之间只有 3 毫秒的差别?这简直是小巫见大巫。

当延迟至关重要时:

  • 游戏(60 FPS = 每帧 16 毫秒预算)
  • 交易(微秒至关重要)
  • VoIP/视频(对抖动敏感)

对于这些情况?请使用 WebSocket(或基于 UDP 的解决方案,例如 WebRTC、WebTransport)。

对于仪表盘、通知、信息流来说,3毫秒的延迟无关紧要。

为什么SSE在大多数应用中胜出

1. 这只是HTTP协议

SSE 运行在 80/443 端口。无需特殊防火墙规则,也无需代理配置。它在所有支持 HTTP 的地方都能正常工作。

WebSocket 需要协议升级:

GET /socket HTTP/1.1
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==

某些企业防火墙会屏蔽Upgrade请求头。某些反向代理不支持 WebSocket。某些 CDN 存在问题。

SSE 协议运行良好。它基于 HTTP 协议。代理服务器可以识别它。CDN 可以缓存它(并添加正确的头部信息)。负载均衡器可以路由它。

真实案例(来自 Stack Overflow):

“我们部署了 WebSocket,在开发环境中运行完美。但在生产环境中,公司网络屏蔽了 ws:// 协议。我们花了两个星期进行调试。后来切换到 SSE,问题立即得到解决。”

2. 内置自动重连功能

SSE(EventSource API):

const eventSource = new EventSource('/stream');
// That's it. Browser handles reconnection automatically.

连接断开?浏览器等待 3 秒后重试。您无需进行任何操作。

WebSocket:

let ws;
let reconnectAttempts = 0;
const maxReconnectDelay = 30000;

function connect() {
  ws = new WebSocket('ws://example.com/socket');

  ws.onopen = () => {
    reconnectAttempts = 0;
    console.log('Connected');
  };

  ws.onclose = () => {
    const delay = Math.min(1000 * Math.pow(2, reconnectAttempts), maxReconnectDelay);
    reconnectAttempts++;
    console.log(`Reconnecting in ${delay}ms...`);
    setTimeout(connect, delay);
  };

  ws.onerror = (error) => {
    console.error('Error:', error);
    ws.close();
  };
}

connect();

你来编写重连逻辑。指数退避。最大尝试次数。抖动以防止出现群体攻击。

或者您可以使用 http://Socket.IO(会增加 40KB 的软件包大小),它会为您完成此操作。

SSE: 1 行代码。WebSocket
 20 行以上代码或外部库。

3. HTTP/2 多路复用

还记得当年对SSE“6个连接数限制”的批评吗?

HTTP/1.1:浏览器限制每个域最多建立 6 个连接。

HTTP/2:一个 TCP 连接,通过多路复用实现无限流。

到 2026 年,HTTP/2 将无处不在:

  • Chrome:97% 的请求使用 HTTP/2
  • 生产服务器:NGINX、Caddy、Cloudflare 默认都使用 HTTP/2。

通过 HTTP/2 进行 SSE 通信 = 无连接数限制。

你可以通过一个 TCP 连接传输 1000 个 SSE 流。高效、快速、开销低。

4. 支持 curl(调试)

上证综:

curl -N https://api.example.com/stream
data: {"message": "Update 1"}

data: {"message": "Update 2"}

^C

您可以使用 curl 调试 SSE 流。无需特殊工具,无需浏览器,只需 curl 即可。

WebSocket:

# Need wscat or similar
npm install -g wscat
wscat -c ws://example.com/socket
Connected (press CTRL+C to quit)
> {"type": "ping"}
< {"type": "pong"}

需要专用工具。操作起来比较复杂。

5. 对CDN友好

SSE 就是 HTTP。CDN理解 HTTP。

想要缓存 SSE 流?请设置标头:

res.setHeader('Cache-Control', 'public, max-age=1');

Cloudflare、Fastly 和 CloudFront 都能透明地处理 SSE。

WebSocket?大多数 CDN 将其视为特例。有些 CDN 完全不支持 WebSocket。配置起来也比较复杂。

实际生产用例

ChatGPT / OpenAI API (2025)

ChatGPT 如何传输回复:

const response = await fetch('https://api.openai.com/v1/chat/completions', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'Authorization': `Bearer ${API_KEY}`
  },
  body: JSON.stringify({
    model: 'gpt-4',
    messages: [...],
    stream: true  // Enable streaming
  })
});

const reader = response.body.getReader();
const decoder = new TextDecoder();

while (true) {
  const { done, value } = await reader.read();
  if (done) break;

  const chunk = decoder.decode(value);
  const lines = chunk.split('\n').filter(line => line.trim());

  for (const line of lines) {
    if (line.startsWith('data: ')) {
      const data = line.slice(6);
      if (data === '[DONE]') continue;
      const parsed = JSON.parse(data);
      console.log(parsed.choices[0].delta.content);
    }
  }
}

这就是SSE。OpenAI使用服务器发送事件(Server-Sent Events)来实现流式完成。

为什么?因为这是单向的。用户通过 POST 请求发送请求,AI 处理响应。SSE 完美解决了这个问题。

Shopify BFCM 实时地图(2022)

挑战:黑色星期五/网络星期一实时销售可视化。数百万用户同时观看实时销售数据。

解决方案: SSE

建筑学:

  • Flink 处理 Kafka 流(销售事件)
  • 汇总数据(按地区划分的销售额、热门产品)
  • SSE服务器向前端推送更新
  • 在 NGINX 负载均衡器后进行水平扩展

结果:

  • 4天内处理了3230亿条事件
  • 数百万个并发的SSE连接
  • 全球延迟小于300毫秒
  • WebSocket 复杂度为零

为什么选择SSE?

“我们只需要服务器到客户端的数据传输。SSE 让我们完全消除了客户端轮询,并充分利用了现有的 HTTP 基础设施。”

http://Split.io 实时功能标志(2025)

应用场景:功能开关平台。客户需要即时更新功能开关状态。

规模:

  • 每月发生1万亿起事件
  • 平均全局延迟小于 300 毫秒
  • 数百万个并发连接

技术: SSE

为什么不用WebSocket?

“标志位在服务器端更改。客户端只需监听。我们不需要双向通信。SSE 让我们能够在 WebSocket 规模下实现 HTTP 的简洁性。”

个人项目:实时日志流

场景:开源日志管理平台。用户可以实时查看到达的日志(类似于tail -f在浏览器中查看)。

要求:

  • 超过1000个用户同时观看不同的日志流
  • 从日志摄取到浏览器的延迟低于 50 毫秒
  • 部署在每月 20 美元的服务器上

实现方式: PostgreSQL LISTEN/NOTIFY + SSE

// Backend: Listen to Postgres
const pgClient = new Client({ connectionString: DB_URL });
await pgClient.connect();

await pgClient.query(`LISTEN logs_${orgId}`);

pgClient.on('notification', (msg) => {
  const log = JSON.parse(msg.payload);
  // Push to connected SSE clients for this org
  sseManager.broadcast(orgId, log);
});

// SSE endpoint
app.get('/api/logs/stream', (req, reply) => {
  const { orgId } = req.user;

  reply.raw.writeHead(200, {
    'Content-Type': 'text/event-stream',
    'Cache-Control': 'no-cache',
    'Connection': 'keep-alive',
    'X-Accel-Buffering': 'no'  // Disable nginx buffering
  });

  const clientId = generateId();
  sseManager.addClient(orgId, clientId, reply.raw);

  // Heartbeat every 30s
  const heartbeat = setInterval(() => {
    reply.raw.write(': heartbeat\n\n');
  }, 30000);

  req.raw.on('close', () => {
    clearInterval(heartbeat);
    sseManager.removeClient(orgId, clientId);
  });
});

结果:

  • 在 4 个虚拟 CPU 服务器上支持 1000 个并发连接
  • p50 延迟:45 毫秒,p95 延迟:120 毫秒
  • CPU 使用率:约 30%
  • 内存:约500MB
  • 无需任何 WebSocket 库。协议复杂度为零。

为什么选择SSE?

日志流从服务器端流向客户端。用户不会通过此流发送日志。如果需要上传日志,则需要单独发送 POST 请求。

SSE堪称完美。简单、快速、可扩展。

WebSocket 真正胜出的时候

说实话,WebSocket 并非总是多此一举。

何时使用 WebSocket:

1. 真正的双向通信

双方持续发送信息。

例如:

  • 多人游戏(玩家持续输入 + 服务器更新)
  • 协作编辑(本地编辑 + 远程编辑同时进行)
  • VoIP/视频通话信令

2. 低延迟至关重要

延迟要求低于10毫秒。

例如:

  • 高频交易
  • FPS游戏(60+ FPS = <16ms预算)
  • 现场拍卖

3. 二进制数据

发送图像、音频、视频帧。

WebSocket 支持二进制:

ws.send(new Uint8Array([1, 2, 3, 4]));

SSE 仅支持文本格式。您需要对二进制数据进行 Base64 编码(会增加 33% 的开销)。

何时使用 SSE:

1. 服务器 → 仅客户端

数据单向流动。

例如:

  • 仪表盘
  • 通知
  • 实时画面
  • AI 流式响应
  • 原木尾矿
  • 股票代码
  • 构建状态
  • 分析

2. 简洁至上

没有重连逻辑,没有帧处理,只有HTTP协议。

3. 适用范围广

企业防火墙、代理服务器、CDN,HTTP 都能正常工作。

4. 调试很重要

curl有效。浏览器开发者工具的网络选项卡清晰地显示了SSE流。

生产陷阱(以及如何解决它们)

1. Nginx 缓冲

问题: Nginx 默认会缓存响应,导致 SSE 事件卡住。

症状:事件以突发形式发生,而不是实时发生。

使固定:

location /api/stream {
    proxy_pass http://backend;
    proxy_buffering off;
    proxy_set_header Connection '';
    proxy_http_version 1.1;
    chunked_transfer_encoding off;
}

或者设置响应头:

res.setHeader('X-Accel-Buffering', 'no');

2. 负载均衡器粘性会话

问题:后端服务器众多。客户端连接到服务器 A。服务器 A 崩溃。客户端重新连接到服务器 B。消息丢失。

解决方案:使用消息后端(Redis Pub/Sub、RabbitMQ、Kafka)。

建筑学:

Client 1 → LB → Server A ─┐
Client 2 → LB → Server B ─┼→ Redis Pub/Sub
Client 3 → LB → Server C ─┘

事件已发布 → Redis → 所有服务器 → 所有已连接的客户端

实现方式(Node.js + Redis):

const redis = require('redis');
const subscriber = redis.createClient();
const publisher = redis.createClient();

// Subscribe to channel
await subscriber.subscribe('updates');

subscriber.on('message', (channel, message) => {
  // Broadcast to all SSE clients connected to THIS server
  sseClients.forEach(client => {
    client.write(`data: ${message}\n\n`);
  });
});

// Publish event (from any server)
publisher.publish('updates', JSON.stringify({ data: 'New event' }));

现在可以横向扩展了。可以添加/移除服务器。客户端不会在意。

3. 心跳

问题:代理服务器会关闭空闲连接(通常为 60-120 秒)。

解决方案:每 30 秒发送一次心跳信号。

const heartbeat = setInterval(() => {
  res.write(': heartbeat\n\n');  // Comment line, ignored by client
}, 30000);

req.on('close', () => clearInterval(heartbeat));

4. 身份验证

问题: EventSource 不支持自定义标头。

解决方案:

A) 使用查询参数:

const eventSource = new EventSource(`/stream?token=${authToken}`);

B) 使用 Cookie:

// Server sets cookie on login
res.cookie('auth', token, { httpOnly: true });

// EventSource automatically sends cookies
const eventSource = new EventSource('/stream');

C) 使用授权 URL(非标准但有效):

const eventSource = new EventSource(`https://${authToken}@api.example.com/stream`);

5. 并发连接数限制

问题: EventSource 计入浏览器连接限制(HTTP/1.1 上每个域 6 个连接)。

解决方案:

A) 使用 HTTP/2(最佳选择 - 无限流量)

B) 使用子域分片:

const shard = userId % 4;
const eventSource = new EventSource(`https://stream${shard}.example.com/events`);

C)关闭未使用的连接:

eventSource.close();  // When no longer needed

实现模式

模式 1:简单广播

使用场景:向所有客户端发送相同数据(股票行情、新闻推送)

const clients = new Set();

app.get('/stream', (req, reply) => {
  reply.raw.writeHead(200, {
    'Content-Type': 'text/event-stream',
    'Cache-Control': 'no-cache'
  });

  clients.add(reply.raw);

  req.raw.on('close', () => {
    clients.delete(reply.raw);
  });
});

// Broadcast function
function broadcast(data) {
  const message = `data: ${JSON.stringify(data)}\n\n`;
  clients.forEach(client => client.write(message));
}

// Example: Update every second
setInterval(() => {
  broadcast({ timestamp: Date.now(), price: Math.random() * 100 });
}, 1000);

模式 2:按用户划分的流

使用场景:针对不同用户提供不同的数据(通知、个性化推送)

const userClients = new Map();  // userId -> Set of connections

app.get('/stream', (req, reply) => {
  const userId = req.user.id;

  reply.raw.writeHead(200, {
    'Content-Type': 'text/event-stream',
    'Cache-Control': 'no-cache'
  });

  if (!userClients.has(userId)) {
    userClients.set(userId, new Set());
  }
  userClients.get(userId).add(reply.raw);

  req.raw.on('close', () => {
    const clients = userClients.get(userId);
    clients.delete(reply.raw);
    if (clients.size === 0) {
      userClients.delete(userId);
    }
  });
});

// Send to specific user
function sendToUser(userId, data) {
  const clients = userClients.get(userId);
  if (!clients) return;

  const message = `data: ${JSON.stringify(data)}\n\n`;
  clients.forEach(client => client.write(message));
}

模式 3:事件类型

使用场景:同一数据流上的多种事件类型(日志+指标+警报)

app.get('/stream', (req, reply) => {
  reply.raw.writeHead(200, {
    'Content-Type': 'text/event-stream',
    'Cache-Control': 'no-cache'
  });

  // Named events
  function sendEvent(eventType, data) {
    reply.raw.write(`event: ${eventType}\n`);
    reply.raw.write(`data: ${JSON.stringify(data)}\n\n`);
  }

  sendEvent('log', { level: 'info', message: 'App started' });
  sendEvent('metric', { cpu: 45, memory: 2048 });
  sendEvent('alert', { severity: 'high', message: 'Disk full' });
});

// Client
const eventSource = new EventSource('/stream');

eventSource.addEventListener('log', (e) => {
  console.log('Log:', JSON.parse(e.data));
});

eventSource.addEventListener('metric', (e) => {
  console.log('Metric:', JSON.parse(e.data));
});

eventSource.addEventListener('alert', (e) => {
  console.log('Alert:', JSON.parse(e.data));
});

迁移:WebSocket → SSE

场景:你已经有了 WebSocket,现在想简化它。该怎么做?

第一步:识别沟通模式

审核您的 WebSocket 使用情况:

// What messages does CLIENT send?
ws.send({ type: 'subscribe', channel: 'updates' });
ws.send({ type: 'ping' });

// What messages does SERVER send?
ws.send({ type: 'update', data: {...} });
ws.send({ type: 'pong' });

如果客户端仅发送:

  • 订阅/配置(连接开始时)
  • Ping/心跳(保持连接)

您可以使用 SSE + HTTP POST。

步骤 2:将客户端→服务器迁移到 HTTP

WebSocket:

ws.send({ type: 'subscribe', channel: 'metrics' });

SSE 同等产品:

// Subscribe via query param or POST
const eventSource = new EventSource('/stream?channel=metrics');

// OR
await fetch('/subscribe', {
  method: 'POST',
  body: JSON.stringify({ channel: 'metrics' })
});
const eventSource = new EventSource('/stream');

步骤 3:将 WebSocket 服务器替换为 SSE

之前(WebSocket):

const WebSocket = require('ws');
const wss = new WebSocket.Server({ port: 3000 });

wss.on('connection', (ws) => {
  ws.on('message', (message) => {
    // Handle client message
  });

  setInterval(() => {
    ws.send(JSON.stringify({ data: 'update' }));
  }, 1000);
});

之后(SSE):

app.get('/stream', (req, reply) => {
  reply.raw.writeHead(200, {
    'Content-Type': 'text/event-stream',
    'Cache-Control': 'no-cache'
  });

  const interval = setInterval(() => {
    reply.raw.write(`data: ${JSON.stringify({ data: 'update' })}\n\n`);
  }, 1000);

  req.raw.on('close', () => clearInterval(interval));
});

步骤 4:更新客户端

之前(WebSocket):

const ws = new WebSocket('ws://localhost:3000');
ws.onmessage = (e) => console.log(JSON.parse(e.data));

之后(SSE):

const es = new EventSource('http://localhost:3000/stream');
es.onmessage = (e) => console.log(JSON.parse(e.data));

结果:代码更简洁,功能不变。

底线

对于 95% 的实时应用而言,SSE 是更好的选择。

为什么:

  • 更简单(仅支持HTTP)
  • 更容易调试(curl 可以正常工作)
  • 自动重连(内置)
  • 在所有地方都能用(没有代理问题)
  • 性能相当(适用于大多数使用场景)
  • 水平缩放(无状态,带背板)

何时使用 WebSocket:

  • 真正的双向(双方频繁发送)
  • 二进制数据(音频/视频帧)
  • 需要超低延迟(<10毫秒)
  • 游戏、协作编辑、VoIP

默认使用 SSE 协议。仅在需要使用 WebSocket 的特定功能时才使用它。

最好的技术并非功能最强大的,而是最简单且能解决你问题的技术。

对于服务器到客户端的流媒体传输,那就是服务器发送事件。


简单。可靠。快速。

有时候,看似平庸的技术才是正确的技术。

关注「索引目录」公众号,获取更多干货。


【声明】内容源于网络
0
0
索引目录
索引目录是一家专注于医疗、技术开发、物联网应用等领域的创新型公司。我们致力于为客户提供高质量的服务和解决方案,推动技术与行业发展。
内容 444
粉丝 0
索引目录 索引目录是一家专注于医疗、技术开发、物联网应用等领域的创新型公司。我们致力于为客户提供高质量的服务和解决方案,推动技术与行业发展。
总阅读1.2k
粉丝0
内容444