Node.js长轮询实现出现异常行为的技术咨询
问题分析与解答
你的代码与现象
先看你实现长轮询的代码:
var lpres1; // store the response object globally // accept long poll call that will block until released by lp_free1 call app.get('/API/lp1', (req, res) => { lpres1 = res; // store response object so we can respond later }); // free up long poll call response and also send the response to this call app.get('/API/lp_free1', (req, res) => { lpres1.setHeader("Access-Control-Allow-Origin", "*"); lpres1.setHeader("Content-Type", "application/json"); lpres1.status(200).send("OK from LP1").end(); res.setHeader("Access-Control-Allow-Origin", "*"); res.setHeader("Content-Type", "application/json"); res.status(200).send("OK").end(); });
你观察到的「异常现象」本质不是Node.js的问题,而是浏览器的同源请求排队机制导致的:
现象背后的原因
- 浏览器对重复GET请求的排队策略:当第一个标签页的
/API/lp1请求处于pending(服务器未响应)状态时,第二个标签页发起的同URL GET请求会被浏览器排队挂起,不会立即发送到服务器——这是浏览器默认的资源优化策略,避免重复请求浪费资源。 - 服务器端实际执行流程:
- 只有第一个
/API/lp1请求真正到达服务器,lpres1被设为第一个请求的res对象,请求挂起。 - 调用
/API/lp_free1时,服务器响应第一个res,第一个标签页收到结果。 - 此时浏览器才会发送排队的第二个
/API/lp1请求,lpres1被覆盖为第二个请求的res对象,请求挂起。 - 再次调用
/API/lp_free1,服务器响应第二个res,第二个标签页收到结果。
- 只有第一个
你的代码的真正隐患
如果绕过浏览器的排队限制(比如给每个/API/lp1请求加不同的URL参数,或者改用POST请求),代码会直接暴露问题:多个/API/lp1请求同时到达服务器时,lpres1会被不断覆盖,最早的请求res对象会丢失,永远无法被响应。
正确的长轮询实现方式
应该用队列存储所有挂起的请求响应对象,而非单个全局变量:
const pendingRequests = []; app.get('/API/lp1', (req, res) => { // 将响应对象加入队列 pendingRequests.push(res); }); app.get('/API/lp_free1', (req, res) => { // 按顺序响应最早挂起的请求 if (pendingRequests.length > 0) { const pendingRes = pendingRequests.shift(); pendingRes.setHeader("Access-Control-Allow-Origin", "*"); pendingRes.setHeader("Content-Type", "application/json"); pendingRes.status(200).send("OK from LP1").end(); } // 响应当前的lp_free1请求 res.setHeader("Access-Control-Allow-Origin", "*"); res.setHeader("Content-Type", "application/json"); res.status(200).send("OK").end(); });
这样每个挂起的/API/lp1请求都会被妥善保存,调用/API/lp_free1时会按顺序响应,不会丢失任何请求。
内容的提问来源于stack exchange,提问作者user3308328
相关产品推荐
相关产品推荐

