几次尝试后 SSE 服务器停止响应
Posted
技术标签:
【中文标题】几次尝试后 SSE 服务器停止响应【英文标题】:SSE server stops responding after a few attempts 【发布时间】:2020-04-02 19:08:54 【问题描述】:当我尝试在 express 上执行 SSE 时,服务器每次尝试 5 次后都会停止响应。 我希望它可以无限期地正常工作。
如果我在一段时间后离开页面,则会出现此错误:
“POST http://localhost:3000/api/updatenet::ERR_EMPTY_RESPONSE”
在服务器上:
"MaxListenersExceededWarning: 可能的 EventEmitter 检测到内存泄漏。 11 个消息监听器添加到 [EventEmitter]。 使用emitter.setMaxListeners() 增加限制"
这两个错误都不会立即出现。
我尝试更改标头并发送不同的状态,但除了破坏正常工作之外没有任何效果。
总的来说,我对表达和节点还很陌生,我真的不知道我在这里做错了什么。
我的服务器是这样设置的:
app.get("/api/update", (req, res, next) =>
res.status(200).set(
"Content-Type": "text/event-stream; charset=utf-8",
"Cache-Control": "no-cache, no-transform",
"Transfer-Encoding": "chunked",
Connection: "keep-alive"
);
app.on("message", data =>
res.write(`data: $JSON.stringify(data)\n\n`);
);
);
app.post("/api/update", (req, res, next) =>
const message = req.body.type;
app.emit("message",
title: "Update",
message,
timestamp: new Date()
);
);
我的客户可以这样近似:
import React, Component from "react";
class Button extends Component
source = new EventSource("api/update");
messageHandler = event =>
console.log(event.data);
;
componentDidMount = () =>
this.source.onmessage = this.messageHandler;
;
render = () => (
<button
onClick=() =>
fetch("/api/update",
method: "POST",
headers:
Accept: "application/json",
"Content-Type": "application/json"
,
body: JSON.stringify(type: "button")
);
/>
);
export default Button;
【问题讨论】:
***.com/questions/9768444/… 【参考方案1】:这部分:
class Button extends Component
source = new EventSource("api/update");
是原因:您一次最多可以同时拥有 5 或 6 个 EventSource 连接。 (SSE(EventSource): why no more than 6 connections?)
通常,您在每次渲染时都会打开新的 EventSource,而不会关闭旧的。每次渲染都会打开新实例。在旧连接关闭之前,您不应该打开新连接。
我使用这种方法: 1. 将您的 EventSource 侦听器存储在 useRef 中,该侦听器保存在所有渲染中。 2. 在你的监听函数上使用回调
const evtSrc = useRef(null)
const listenEvt = useCallback(() =>
if (!evtSrc.current)
evtSrc.current = new EventSource("api/update");
, [])
-
然后您要求使用 useEffect 挂钩在挂载时创建新的 EventSource 连接,并在每次卸载时关闭它:
useEffect(() =>
listenEvt() // componentDidMount
return () => evtSrc.current.close() // componentDidUnmount
希望这会有所帮助。
【讨论】:
onmessage方法应该放在哪里?在evtSrc.current = new EventSource("api/update");
? 之后进入 useCallback 钩子?
是的,在那个函数中你定义了所有的 EventSource 方法。
我设法解决了这个问题,但不幸的是没有使用这个答案:我注意到我只是在发布到服务器时忘记关闭连接。问题出在服务器端,而不是客户端。您所说的重新渲染在类组件中不是正确的,而仅在功能组件中是正确的。无论如何,感谢您花时间回答我的问题。【参考方案2】:
我设法解决了这个问题:我在发布到服务器时忘记关闭连接。 这个:
app.post("/api/update", (req, res, next) =>
const message = req.body.type;
app.emit("message",
title: "Update",
message,
timestamp: new Date()
);
);
变成这样:
app.post("/api/update", (req, res, next) =>
const message = req.body.type;
app.emit("message",
title: "Update",
message,
timestamp: new Date()
);
res.end();
);
【讨论】:
以上是关于几次尝试后 SSE 服务器停止响应的主要内容,如果未能解决你的问题,请参考以下文章
socket.io 在 x 秒/第一次尝试获取响应失败后停止重新发出事件