如何在本地JavaScript和node.js中使用长轮询?

15

我需要为一个聊天应用程序实现长轮询(long polling)。 我搜索过,但我只找到如何使用JQueryJavaScript中实现它。 我该如何仅使用原生 JavaScriptnode.js来实现它? 你能引导我一些相关的文章或资料吗?


我建议您查看套接字(Socket)而不是长轮询(long polling),它比长轮询更有效率。https://dev59.com/umkw5IYBdhLWcg3wPYMP (附言:我最近才知道什么是长轮询,所以无法回答您的问题) - Frankusky
1
嗨,我的项目要求不允许使用套接字,尽管套接字更专业,并且我在之前的项目中使用过它。 - user8244016
1个回答

24

问题: 如何在本地的Javascript中使用长轮询,在nodeJS中实现?

回答: 首先,我想你需要了解长轮询模型的工作原理。如果您还没有任何线索,那么RFC-6202规范是一个很好的起点。

它涉及到客户端向服务器发送一个请求,并等待直到响应返回。

从规范中,我们知道客户端首先必须发出一个http请求,该请求具有无限或至少很高的超时值。然后,预期您的nodeJs应用程序将所有传入的请求存储到数据结构(基本上是一个暂存区)。您的应用程序将基本上保留所有response对象,直到触发某个事件,然后适当地回复这些响应。

考虑下面的伪代码:

const express = require('express');
const app = express();
const bodyParser = require('body-parser');

var requestCounter = 0;

var responses = {
  /* Keyed by room Id =*/
  "room_abc" : [ /* array of responses */]
};

app.get('/', function (req, res) {
    requestCounter += 1;

    var room = /* assuming request is for room_abc */ "room_abc";

    // Stash the response and reply later when an event comes through
    responses[room].push(res);

    // Every 3rd request, assume there is an event for the chat room, room_abc.
    // Reply to all of the response object for room abc.
    if (requestCounter % 3 === 0) {
        responses["room_abc"].forEach((res) => {
            res.send("room member 123 says: hi there!");
            res.end();
        });
    }
});

app.use(bodyParser.text({ type: 'text/*' }));
app.use(bodyParser.json());

app.listen(9999, function () {
    console.log('Example app listening on port 9999!')
})

在这里写一个可工作的示例相对耗时,但是上面的代码是如何在 NodeJS 中实现长轮询的好例子。

如果你已经安装了 postman 或者 curl ,你可以使用方法 GEThttp://localhost:9999/ 进行 HTTP 调用。你会注意到,在前两次调用中,你不会得到响应,只有在第三次调用时,你才会收到所有之前和当前调用的响应。

这里的想法是首先将请求的 response 对象存储起来,当事件出现时(假设每隔三个 HTTP 调用),然后循环遍历所有的响应并回复它们。对于聊天应用程序的情况,触发响应的事件可能是某人向聊天室发送消息。


你好,感谢您的回答。但我有一个问题,请问当某个用户发送消息到房间时,我能否用检查计数器值的方式替换最后一个条件,即如果计数器值大于我已经拥有的值,则表示有新消息应该显示在房间聊天中,这样可以吗?还有一件事,请问如何使用本机JavaScript在客户端“调用”服务器? - user8244016
我猜你可能需要两个端点。一个用于客户端停留并等待响应,如上所示。然后,另一个用于客户端发布聊天消息。当有消息被编写时,你会想要遍历该房间中的所有response对象,并适当地进行回复。 - Samuel Toh
关于你的另一个问题,关于如何使用客户端发送HTTP REST请求。请参考https://developer.mozilla.org/en-US/docs/Web/API/Request 上的示例。 - Samuel Toh
15
您的代码示例没有展示长轮询,实际上展示的是既不是长轮询也不是短轮询的一种方式。要使其成为长轮询,如果在发出请求时数据不可用,则应保持连接,当数据变得可用时,发送响应。如果超时前数据仍未可用,则应使用超时终止连接。 - Rafael Eyng

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接