我有一个非常简单的节点服务,它公开了一个旨在使用服务器发送事件(SSE)连接的终结点,还有一个非常基本的ReactJs客户端通过EventSource.onmessage对其进行使用。
首先,当我在updateAmountState(Chrome Dev)中设置调试点时,看不到它。
其次,我得到了net :: ERR_INCOMPLETE_CHUNKED_ENCODING 200(确定)。根据{{3}},“ Chrome中的ERR_INCOMPLETE_CHUNKED_ENCODING通常表示在写入响应主体的过程中,应用程序抛出了未捕获的异常”。然后,我检查了服务器端,看是否发现任何错误。好吧,我在两个setTimeout(()=> {...中的server.js中的几个地方都设置了断点,我看到它是定期运行的。我希望每行只运行一次。所以前端似乎是尝试永久调用后端并获得一些错误。
ReactJs中的整个应用程序以及NodeJs中的服务器的整个应用程序都可以在https://github.com/aspnet/KestrelHttpServer/issues/1858中找到。
后端:
const http = require("http");
http
.createServer((request, response) => {
console.log("Requested url: " + request.url);
if (request.url.toLowerCase() === "/coins") {
response.writeHead(200, {
Connection: "keep-alive",
"Content-Type": "text/event-stream",
"Cache-Control": "no-cache"
});
setTimeout(() => {
response.write('data: {"player": "Player1", "amount": "90"}');
response.write("\n\n");
}, 3000);
setTimeout(() => {
response.write('data: {"player": "Player2", "amount": "95"}');
response.write("\n\n");
}, 6000);
} else {
response.writeHead(404);
response.end();
}
})
.listen(5000, () => {
console.log("Server running at http://127.0.0.1:5000/");
});
前端:
import React, { Component } from "react";
import ReactTable from "react-table";
import "react-table/react-table.css";
import { getInitialCoinsData } from "./DataProvider";
class App extends Component {
constructor(props) {
super(props);
this.state = {
data: getInitialCoinsData()
};
this.columns = [
{
Header: "Player",
accessor: "player"
},
{
Header: "Amount",
accessor: "amount"
}
];
this.eventSource = new EventSource("coins");
}
componentDidMount() {
this.eventSource.onmessage = e =>
this.updateAmountState(JSON.parse(e.data));
}
updateAmountState(amountState) {
let newData = this.state.data.map(item => {
if (item.amount === amountState.amount) {
item.state = amountState.state;
}
return item;
});
this.setState(Object.assign({}, { data: newData }));
}
render() {
return (
<div className="App">
<ReactTable data={this.state.data} columns={this.columns} />
</div>
);
}
}
export default App;
我在chrome上看到的异常:
https://github.com/jimisdrpc/hello-pocker-coins
所以我的直接问题是:为什么我得到ERR_INCOMPLETE_CHUNKED_ENCODING 200?我在后端还是前端缺少某些东西?
一些提示可能对我有帮助:
为什么我根本没有使用websocket,为什么我看到websocket处于挂起状态?我知道基本的区别(websocket是双向的,从前到后,从后到前,这是一个不同的协议,而SSE在http上运行并且仅从前到后)。但是我根本不打算使用websocket。 (请参见打印屏幕下方的蓝线)
为什么我看到0字节和236字节的事件源都失败了。我了解当我编写“ this.eventSource = new EventSource(“ coins”);“时,事件源正是我要使用的源。 (请参阅下面的打印屏幕中的阅读行)
至少对我来说很奇怪,有一段时间,当我杀死发球时,我看到了updateAmountState方法被唤醒。
如果在浏览器中调用localhost:5000 / coins,我可以看到服务器回答了响应(两个json字符串)。我可以假设我对服务器进行了正确的编码,并且错误在前端中是排他性的吗?
答案 0 :(得分:4)
这是您问题的答案。
websocket
正在运行,与您在此处发布的代码无关。它可能与您在应用程序中使用的另一个NPM软件包有关。通过查看网络请求中的标头,您也许可以弄清楚它的来源。eventsource
请求失败的最可能原因是它们超时。在闲置两分钟后,Chrome浏览器将终止闲置的流。如果要保持活动状态,则需要添加一些代码,以至少每两分钟一次的时间将某些内容从服务器发送到浏览器。为了安全起见,最好每分钟发送一次。下面是您需要的示例。如果在服务器代码中的第二个setTimeout
之后添加它,它应该可以满足您的需求。const intervalId = setInterval(() => {
res.write(`data: keep connection alive\n\n`);
res.flush();
}, 60 * 1000);
req.on('close', () => {
// Make sure to clean up after yourself when the connection is closed
clearInterval(intervalId);
});
updateAmountState
方法被调用。如果您不能始终看到它,则可能不是主要问题,但是如果服务器在完成之前停止运行,则可能有助于清理setTimeout
。您可以通过将它们声明为变量,然后在关闭事件处理程序中将变量名传递给clearTimeout
来实现此目的,类似于在上面的#2示例中对间隔所做的操作。答案 1 :(得分:1)
我自己不是Node.js专家,但是您似乎想念“'Connection':'keep-alive'”和其后的“ \ n”,即:
response es.writeHead(200, {
'Content-Type': 'text/event-stream',
'Cache-Control': 'no-cache',
'Connection': 'keep-alive'
});
response.write('\n');
请参见https://jasonbutz.info/2018/08/server-sent-events-with-node/。希望它能起作用!