Issue and phenomenon
When I use server sent events to the react client: the event messages can be received when I access the backend by request url directly from the browser address bar, but can never be received by the front end application, and the EventStream in Chrome Dev-Tool is empty; However, once I stop the backend server, ALL the messages are flushed/sent to the client at one time. It seems that the messageS are buffered or pended somewhere.
The node.js/express test code:
// send events to client router.get('/events', async (req, res) => { res.writeHead(200, { 'Content-Type': 'text/event-stream', 'Cache-Control': 'no-cache', 'Connection': 'keep-alive' }); setInterval(() => { res.write(`event: message\n`); res.write(`data: ${new Date()}"}\n\n`); }, 2000); }
The client javascript:
// receive events from server-side const sse = new EventSource('/events'); sse.onmessage = (e) => { const anaStates = JSON.parse(e.data); console.log('WHERE ARE THE EVENTS???????'); // this line never appears in Dev-tool console }; sse.onopen = (e) => { console.log('event is opened', e); } // this log message shows eventSource is open sse.onerror = (e) => { console.log('event has errors', e); }
Analysis
- I have already enabled CORS by using cors middleware at the backend;
- The proxy works fine, as the other requests to the endpoints are avalaible;
- The Cache Control option settings of the response HTTP header of server-side are exactly the same with the sample code of MDN docs and it looks right.
I didn't get an answer from others or google sse, eventSource, cors or proxy. One suggested way is to disable CORS of browser:
$ google-chrome --disable-web-security
But I don't think this is a good way as we need to put things online eventually, it didn't work for debugging as well when I tried.
Solutions
This bugged me serveral hours. I luckily found two solutions by changing code line by line:
- Use full URL to request the events (may not be decent, but it works) from client side:
const sse = new EventSource('http://localhost:8080/events');
-
Set the server-side Cache Control Header to no-transform:
'Cache-Control': 'no-cache', --> 'Cache-Control': 'no-transform',
or
'Cache-Control': 'no-cache', --> 'Cache-Control': 'no-cache, no-transform',
I cannot fully understand why the no-transform directive matters here. It seems that the stream Event message is compressed in gzip format(see the respond header: Content-Encoding: gizp) and cannot be decompressed automatically when using no-cache directive(or by default), so it is buffered??; when we add no-transform directive, the message is not compressed, so ... won't be buffered??
By searching no-transform with sse, I got this:
- https://www.npmjs.com/package/ssestream-no-cache-transform
- https://github.com/facebook/create-react-app/issues/1633
Anyway, these are solutions to the issue. If anyone can give a good explanation, please leave your comment here.
Comments