How to check if connection was aborted in node.js

2019-02-03 01:31发布

问题:

I'm making some long polling with node.js.
Basically, node.js server accepts request from the user and then checks for some updates. If there're no updates, it will check them after the timeout.
But what if user has closed his tab, or went to another page? In my case, the script continues working.
Is there a way in node.js to check or detect or to catch an event when user has aborted his request (closed the connection)?

回答1:

You need to use req.on('close', function(err) { ... }); instead of req.connection.on('close', function(err) { ... });

There is a very important distinction. req.on() adds a listener to this request while req.connection.on(), you add a listener to the (keep-alive) connection between the client and the server. If you use req.connection.on(), every time the client re-uses a connection, you add one more listener to the same connection. When the connection is finally aborted, all listeners are fired.

Function scoping typically keeps you safe from this screwing up your server logic, but it's a dangerous thing nevertheless. Fortunately at least NodeJS 0.10.26 is smart enough to warn the user of this:

(node) warning: possible EventEmitter memory leak detected. 11 listeners added. Use emitter.setMaxListeners() to increase limit.
Trace: 
  at Socket.EventEmitter.addListener (events.js:160:15)
  at Socket.Readable.on (_stream_readable.js:689:33)
  ...


回答2:

Thanks to Miroshko's and yojimbo87's answers I was able to catch the 'close' event, but I had to make some additional tweaks.

The reason why just catching 'close' event wasn't fixing my problem, is that when client sends the request to the node.js server, the server itself can't get information if the connection is still open until he sends something back to the client (as far as I understood - this is because of the HTTP protocol).
So, the additional tweak was to write something to the response from time to time.
One more thing that was preventing this to work, is that I had 'Content-type' as 'application/json'. Changing it to 'text/javascript' helped to stream 'white spaces' from time to time without closing the connection.
In the end, I had something like this:

var server = http.createServer(function(req,res){    
    res.writeHead(200, {'Content-type': 'text/javascript'});

    req.connection.on('close',function(){    
       // code to handle connection abort
    });

    /**
     * Here goes some long polling handler
     * that performs res.write(' '); from time to time
     */

    // some another code...
});
server.listen(NODE_PORT, NODE_LISTEN_HOST);

My original code is much bigger, so I had to cut it a lot just to show the sensitive parts.

I'd like to know if there are better solutions, but this is working for me at the moment.



回答3:

Is there a way in node.js to check or detect or to catch an event when user has aborted his request (closed the connection)?

You can try to use http.ServerRequest close event. Simple example:

var http = require("http"),
    util = require("util");

var httpServer = http.createServer(function(req, res) {
    util.log("new request...");

    // notify me when client connection is lost
    req.on("close", function(err) {
        util.log("request closed...");
    });

    // wait with response for 15 seconds
    setTimeout(function() {
        res.writeHead(200, {'Content-Type': 'text/plain'});
        res.write("response");
        res.end();

        util.log("response sent...");
    }, 15000);
});
httpServer.listen(8080);
util.log("Running on 8080");


回答4:

Seems that your question is very similar to this one:

NodeJS HTTP request connection's close event fired twice

try

request.connection.on('close', function () {
  ... 
}); 


回答5:

I'm using Express.js (~4.10.6) and the following code is working fine for me:

//GET Request:
app.get('/', function(req, res){
    req.on('close', function(){
        console.log('Client closed the connection');
    });
});

As soon as I close the browser's tab, the browser closes the connection, and the callback function gets executed as expected.