Resovle buffered/pended/blocked eventSource messages

2020年01月20日 1789Browse 1Like 0Comments

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.

SSE Blocked

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:

  1. 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');

  2. 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.

Sunflower

Stay hungry stay foolish

Comments