SSE 服务器在几次尝试后停止响应
SSE server stops responding after a few attempts
当我尝试在 express 上执行 SSE 时,服务器每次都在恰好 5 次尝试后停止响应。
我想让它无限期地工作。
如果我在一段时间后不理会该页面,则会出现此错误:
"POST http://localhost:3000/api/update net::ERR_EMPTY_RESPONSE"
在服务器上:
"MaxListenersExceededWarning: Possible EventEmitter
memory leak detected. 11 message listeners added to [EventEmitter].
Use emitter.setMaxListeners() to increase limit"
两个错误都不会立即出现。
我尝试更改 headers 并发送不同的状态,但没有任何效果,只是打破了正在运行的状态。
总的来说,我对表达和节点还很陌生,我真的不知道我做错了什么。
我的服务器 set-up 是这样的:
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;
这部分:
class Button extends Component {
source = new EventSource("api/update");
原因是:您一次最多可以同时连接 5 或 6 个 EventSource。
(SSE(EventSource): why no more than 6 connections?)
通常,每次渲染都会打开新的 EventSource,而不会关闭旧的 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
}
希望这对您有所帮助。
我设法解决了问题:我在发送到服务器时忘记关闭连接。
这个:
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();
});
当我尝试在 express 上执行 SSE 时,服务器每次都在恰好 5 次尝试后停止响应。 我想让它无限期地工作。
如果我在一段时间后不理会该页面,则会出现此错误:
"POST http://localhost:3000/api/update net::ERR_EMPTY_RESPONSE"
在服务器上:
"MaxListenersExceededWarning: Possible EventEmitter memory leak detected. 11 message listeners added to [EventEmitter]. Use emitter.setMaxListeners() to increase limit"
两个错误都不会立即出现。
我尝试更改 headers 并发送不同的状态,但没有任何效果,只是打破了正在运行的状态。
总的来说,我对表达和节点还很陌生,我真的不知道我做错了什么。
我的服务器 set-up 是这样的:
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;
这部分:
class Button extends Component {
source = new EventSource("api/update");
原因是:您一次最多可以同时连接 5 或 6 个 EventSource。 (SSE(EventSource): why no more than 6 connections?)
通常,每次渲染都会打开新的 EventSource,而不会关闭旧的 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
}
希望这对您有所帮助。
我设法解决了问题:我在发送到服务器时忘记关闭连接。 这个:
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();
});