Long Polling 是一种客户端与服务器交互的技术,服务器保持 HTTP 请求打开直到新数据出现或超时。与定期轮询不同,服务器不会立即返回空响应,而是等待事件发生以向客户端发送数据。根据 MDN Web Docs, 2024,Long Polling 在 WebSocket 不可用或冗余的实时应用中仍然是一种广受欢迎的解决方案。
要点
Long Polling 是客户端-服务器架构中的一种交互模式,客户端发起 HTTP 请求,服务器延迟发送响应直到新数据出现或指定超时到期。收到响应后,客户端立即发送下一个请求,产生持续连接的效果。
Long Polling 技术是 Short Polling 的演进发展,用于减少空 HTTP 请求的数量。在传统轮询中,客户端每隔 N 秒发送请求,即使没有新数据服务器也会响应。在 Long Polling 中,服务器使用连接保持机制,大幅减少无用流量。
在 2011 年 WebSocket 出现之前,Long Polling 是网络上组织实时通信的主要方式。Facebook 和 Gmail 等公司在 2010 年代初使用这种技术进行聊天和通知。根据 High Performance Browser Networking (Grigorik, 2013) 的研究,Long Polling 处理了当时大型 Web 应用中高达 95% 的实时连接。
客户端向服务器发送标准 HTTP 请求。服务器收到请求后不立即返回响应 — 将请求放入等待队列。当服务器上发生事件(新消息、数据更改)时,服务器形成响应并发送给客户端。客户端收到响应后,立即创建新的Long Polling 请求,循环重复。
Long Polling 按以下步骤序列工作。客户端向服务器端点发送 HTTP GET 请求。服务器收到请求后检查事件队列中是否有新数据。如果没有数据,服务器保持请求处于等待状态,不立即发送响应。保持机制取决于服务器的实现 — 最常使用带回调的异步处理或事件驱动架构。
当服务器端发生事件(例如用户在聊天中发送消息)时,服务器形成包含这些数据的 HTTP 响应并结束连接。客户端收到响应,处理数据并立即发起新请求。如果在等待期间没有数据出现,服务器在超时后发送空响应,客户端也重新创建连接。超时通常为 30-60 秒,以平衡负载和延迟。
Long Polling 配置的关键参数是等待超时。超时过短(少于 10 秒)会导致请求数量增加,使技术接近 Short Polling。过长(超过 120 秒)可能导致中间代理和负载均衡器断开连接。大多数场景的推荐值为 30-45 秒。
如果在一次 Long Polling 请求期间服务器上发生了多个事件,服务器必须在一次响应中全部传递,或在客户端组织事件队列。为此使用事件缓冲:服务器收集请求保持期间发生的事件,作为数据数组在响应体中传递。
让我们看看使用现代 Fetch API 在客户端实现 Long Polling 的简单例子。客户端函数发送请求并在收到响应后递归调用自身。
async function longPoll(url) {
try {
const response = await fetch(url);
const data = await response.json();
handleData(data);
longPoll(url);
} catch (error) {
console.error("Long Polling 错误", error);
setTimeout(() => longPoll(url), 3000);
}
}
function handleData(data) {
if (data.events && data.events.length > 0) {
data.events.forEach(event => {
console.log("新事件:", event);
});
}
}
longPoll("/api/events");
此代码创建无限 Long Polling 循环:收到响应后,函数立即发送新请求。连接错误时,在重试前设置三秒延迟以避免服务器雪崩负载。
在服务器端,需要保持请求直到事件出现或超时到期。在 Node.js 中使用 EventEmitter 的实现示例演示了此机制。
const express = require("express");
const EventEmitter = require("events");
const app = express();
const eventBus = new EventEmitter();
app.get("/api/events", (req, res) => {
const timeout = setTimeout(() => {
res.json({ events: [] });
}, 30000);
eventBus.once("new-event", (data) => {
clearTimeout(timeout);
res.json({ events: [data] });
});
});
app.post("/api/events", (req, res) => {
eventBus.emit("new-event", req.body);
res.send({ status: "ok" });
});
app.listen(3000);
服务器部分使用 EventEmitter 在新数据出现时通知等待的 Long Polling 连接。达到 30 秒超时后,服务器返回空事件数组,客户端创建新请求。
Long Polling 在需要实时数据传递但因技术或基础设施原因无法使用 WebSocket 的场景中使用。最常见的情况 — 阻止 WebSocket 连接的企业代理和防火墙,以及服务器端协议支持受限的环境。
选择 Long Polling 的关键因素是向后兼容性。所有 HTTP 客户端和服务器都支持此方法,使其成为无需额外依赖的实时通用解决方案。根据 HTTP Archive(2024),约 8% 的网站继续使用 Long Polling 实现基本的实时功能。
Long Polling 和 Short Polling 解决相同的任务 — 将数据从服务器传递到客户端 — 但在机制和效率方面有根本区别。Short Polling 使用固定轮询间隔,客户端以相等时间间隔发送 HTTP 请求,无论服务器上是否有新数据。
| 特性 | Long Polling | Short Polling |
|---|---|---|
| 响应发起 | 服务器在事件时发送数据 | 服务器响应每个客户端请求 |
| 传递延迟 | 最小,最多 1 秒 | 取决于轮询间隔,3-60 秒 |
| 请求数量 | 每次事件或超时 1 个请求 | 单位时间内 N 个请求(固定) |
| 空闲时流量 | 低(一个打开的请求) | 高(每 N 秒的请求) |
| 服务器负载 | 保持连接 | 处理频繁请求 |
| 实现复杂性 | 中等(异步处理) | 低(普通 HTTP 请求) |
Short Polling 实现更简单,但在相同的数据更新频率下对服务器和网络产生更大的负载。如果需要低于 5 秒的延迟,Short Polling 每分钟生成几十个请求,而 Long Polling 每次事件或超时使用一个请求。对于事件稀疏的应用程序,Long Polling 在流量方面效率更高。
WebSocket 是一种完整的双向实时协议,在初始 HTTP 握手后通过 TCP 工作。与 Long Polling 不同,WebSocket 建立一个永久连接,允许服务器随时向客户端发送数据而无需创建新的 HTTP 请求。
Long Polling 和 WebSocket 之间的选择取决于几个因素。兼容性:Long Polling 可通过所有代理和防火墙工作,WebSocket 可能被企业网络阻止。性能:WebSocket 具有更小的开销(每帧 2 字节,而完整 HTTP 头为数百字节),在高消息频率下至关重要。可扩展性:Long Polling 因保持多个连接而需要更多服务器端资源,WebSocket 每会话使用固定连接。
根据 Mozilla Developer Network(2024),WebSocket 从 2011-2015 版本开始被所有现代浏览器支持,但企业代理(如 Symantec Blue Coat)仍在 15-20% 的企业网络中阻止它,保持 Long Polling 作为后备解决方案的相关性。
常见问题
Long Polling 就是客户端请求服务器“有新数据时回答”,服务器保持连接打开,等待事件。一旦数据出现,服务器做出响应,客户端立即再次提出同样的问题。
在 Short Polling 中,客户端每 N 秒询问服务器是否有数据,即使没有数据也是如此。在 Long Polling 中,客户端询问一次,服务器仅当数据真正出现时才响应。Long Polling 创建更少的空请求并减少网络负载。
当 WebSocket 不可用时应使用 Long Polling:在阻止非 HTTP 协议的企业网络中,需要与旧浏览器向后兼容或托管方有限制时。WebSocket 对于高频数据交换更高效。
推荐的 Long Polling 超时为 30-45 秒。较小的值(10-15 秒)增加请求数量,较大的值(60 秒以上)可能因中间负载均衡器断开连接而有风险。超时值取决于网络架构和延迟要求。
Long Polling 的主要缺点 — 保持数千个连接时服务器内存消耗高,水平扩展困难(需要集中式事件队列),以及缺乏真正的双向通信 — 向服务器发送数据需要单独的 POST 请求。
总结
我们将开发一款交钥匙移动应用程序
IT Sectr自2017年以来为初创企业和企业打造iOS和Android应用程序。我们将为您提供咨询并提出最佳解决方案。