服务器发送事件(Server Sent Events)在React和Node.js中无法接收流消息

6

我的设置非常简单。
NodeJs

export default class StreamController {
    public static newMessage = async (req: Request, res: Response) => {
        const { userid } = req.params;
        res.writeHead(200, {
            "Connection": "keep-alive",
            "Content-Type": "text/event-stream",
            "Cache-Control": "no-cache",
        });
        setInterval(async () => {
            console.log(await MessagesController.hasNewMessage(userid));
            res.write(`${JSON.stringify({ hasUnread: await MessagesController.hasNewMessage(userid) })}`);
            res.write("\n\n");
        }, 5000);
    }
}

React

 constructor() {
        super();
        const uid = getUserId();
        const eventSource = new EventSource(`http://localhost:8080/stream/messages/${uid}`)

        eventSource.onmessage = (e) => {
            console.log(e)
        }
    }

我看到流已经打开,但从服务器没有传递任何事件,而服务器端发出了数据。我做错了什么吗?


你有没有看到服务器端发送任何数据之前的控制台日志(console.log)?尝试将\n\n放在同一个write中(我不认为这是原因,但值得一试)。 - Amit Wagner
@AmitWagner,使用setInterval的console.log显示数据存在。 - andrey.shedko
尝试添加onerror事件,看看是否会出现任何错误。 - Amit Wagner
1个回答

11

您正在服务器端传递data,但未将事件名称作为event进行传递。以下是我解决该问题的方法(简化复制):

服务器

app.get('/stream', (req, res) => {
  console.log('request received');
  res.writeHead(200, {
    "Connection": "keep-alive",
    "Content-Type": "text/event-stream",
    "Cache-Control": "no-cache",
  });
  setInterval(async () => {
    res.write('event: ping\n');  // added these
    res.write(`data: ${JSON.stringify({ hasUnread: true })}`);
    res.write("\n\n");
  }, 5000);
});

客户:

constructor(props) {
  super(props);
  const eventSource = new EventSource(`http://localhost:3030/stream`);
  eventSource.onopen = e => {
    console.log(e);
  }
  eventSource.onmessage = e => {
    console.log('onmessage');
    console.log(e);
  }
  eventSource.addEventListener('ping', e => {
    console.log(e);
  });
}

ping事件将会每5秒触发一次。

现在,如果你想调用eventSource.onmessage,你应该在服务器端将event命名为message

...
setInterval(async () => {
  res.write('event: message\n');  // message event
  res.write(`data: ${JSON.stringify({ hasUnread: true })}`);
  res.write("\n\n");
}, 5000);
...

现在您将在控制台中看到:

onmessage MessageEvent {..., data: "{'hasUnread': true}", ...}

请注意,在这种情况下,ping事件将不再被触发。更多信息请参见此处


没错,我们需要添加 res.write('event: message\n'); 不幸的是,没有人在他们的 NPM 包中提到过这一点。 - Rohit Parte

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