Wednesday, 3 May 2017

HTML5 EventSource and NodeJs not closing on some networks

Context

I have a Javascript app that opens an SSE connection to a NodeJs (express) server through the EventSource object. I got everything to work in no time and life was good... until demo day (today).

All of our tests and demo rehearsals had been done on home (or "normal") WIFI networks (however the NodeJS server was not on the LAN, it's hosted somewhere on the web), but the demo was in a school. The network architecture there was probably a bit more complex (firewalls and what not). I can't really say because I didn't get a chance to ask and my limited knowledge of networks didn't help much.

The thing is... I did the demo with 2 different NodeJs apps, one of which I had corrected a bug in the SSE connection that kept timing out using request.setTimeout(0). The first app worked as expected (even though the connection times out after 2 minutes), but on the second app, when the client-side code executed the EventSource.close() method, the NodeJs request.on('close', ...) event would not get called.

I then switched to my phone's tethering network for the demo and everything started working again. I also tested everything when I got back home with the same successful results. So the problem has to be coming from the school's network.

Here's some code to help clarify things :

Code

Client-side (Javascript in browser)

let serverConnection = new EventSource(theUrl);
// some code...
serverConnection.close();

Server-side (NodeJs)

router.get('/connect', function(req, res){

    // Important to avoid net::ERR_INCOMPLETE_CHUNKED_ENCODING error.
    // Inspired from https://github.com/nodejitsu/node-http-proxy/issues/921
    req.setTimeout(0); // Disable timeout (default was 2 min)
    // ^^^ BUG FIX (only in second version of app)

    // send headers for event-stream connection (SSE)
    res.writeHead(200, {
        'Content-Type': 'text/event-stream',
        'Cache-Control': 'no-cache',
        'Connection': 'keep-alive'
    });
    res.write('\n'); // Important!
    
    req.on("close", function () { // Connection closed (possibly by client)

        // NOT BEING EXECUTED (only in second version of app)
    });

})

Question

So my questions are :

  1. What could be causing the behavior where the req.on('close', ...) event is not getting called and how can I recreate the conditions at home?
  2. How can I fix it without removing the req.setTimeout(0); (basically using HTTP headers or properties)?

I know I could fix my problem by messaging the server to close the connection, but I really don't want to do that.



via Simon Corcos

No comments:

Post a Comment