I have a very simple node service exposing an endpoint aimed to use Server Send Events (SSE) connection and a very basic ReactJs client consuming it via EventSource.onmessage.
Firstly, when I set a debug point in updateAmountState (Chrome Dev) I can't see it evoked.
Secondly, I am getting net::ERR_INCOMPLETE_CHUNKED_ENCODING 200 (OK). According to https://github.com/aspnet/KestrelHttpServer/issues/1858 "ERR_INCOMPLETE_CHUNKED_ENCODING in chrome usually means that an uncaught exception was thrown from the application in the middle of writing to the response body". Then I checked the server side to see if I find any error. Well, I set break point in few places in server.js in both setTimeout(() => {... and I see it run periodically. I would expected each line to run once only. So it seems the front-end is trying permanently call the backend and getting some error.
The whole application, both front in ReactJs and the server in NodeJs can be found in https://github.com/jimisdrpc/hello-pocker-coins.
backend:
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/");
});
frontend:
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;
The exception I can see on chrome:
So my straight question is: why I am getting ERR_INCOMPLETE_CHUNKED_ENCODING 200? Am I missing something in the backend or in the frontend?
Some tips may help me:
Why do I see websocket in oending status since I am not using websocket at all? I know the basic difference (websocket is two-way, from front to back and from back to front and is a diferent protocol while SSE run over http and is only back to front). But it is not my intention to use websocket at all. (see blue line in printscreen belllow)
Why do I see eventsource with 0 bytes and 236 bytes both failled. I understand that eventsource is exactly what I am trying to use when I coded "this.eventSource = new EventSource("coins");". (see read line in printscreen bellow)
Very strange at least for me, some time when I kill the serve I could see updateAmountState methond evoked.
If call the localhost:5000/coins in browser I can see the server answers the response (both json strings). Can I assume that I coded properly the server and the erros is something exclusevely in the frontend?
I'm not a Node.js expert myself, but it looks like you miss "'Connection': 'keep-alive'" and a "\n" after that - i.e.:
response es.writeHead(200, {
'Content-Type': 'text/event-stream',
'Cache-Control': 'no-cache',
'Connection': 'keep-alive'
});
response.write('\n');
see https://jasonbutz.info/2018/08/server-sent-events-with-node/. Hope it works!