web-dev-qa-db-ja.com

node.jsサーバーで接続が中止されたかどうかを確認する方法

Node.jsで長いポーリングを行っています。
基本的に、node.jsサーバーはユーザーからのリクエストを受け入れ、いくつかの更新をチェックします。更新がない場合は、タイムアウト後に更新がチェックされます。
しかし、ユーザーがタブを閉じたり、別のページに移動したりした場合はどうなりますか?私の場合、スクリプトは引き続き機能します。
node.jsに、ユーザーがリクエストを中止した(接続を閉じた)ときにイベントをチェック、検出、またはキャッチする方法はありますか?

24
WallTearer

Miroshko'syojimbo87'sの回答のおかげで、「閉じる」イベントをキャッチできましたが、さらに微調整する必要がありました。

「close」イベントをキャッチしただけでは問題が解決しなかった理由は、クライアントがnode.jsサーバーにリクエストを送信するときに、接続がまだ開いている場合はサーバー自体が情報を取得できないためです。彼はクライアントに何かを送り返します(私が理解している限り、これはHTTPプロトコルによるものです)。
それで、追加の微調整は時々応答に何かを書くことでした。
これが機能するのを妨げていたもう1つのことは、「application/json」として「Content-type」があったことです。これを「text/javascript」に変更すると、接続を閉じずに「空白」を時々ストリーミングするのに役立ちました。
結局、私は次のようなものを持っていました:

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);

私の元のコードははるかに大きいので、敏感な部分を表示するためだけにそれをたくさんカットしなければなりませんでした。

より良い解決策があるかどうか知りたいのですが、これは現在私のために働いています。

19
WallTearer

req.on('close', function(err) { ... });の代わりにreq.connection.on('close', function(err) { ... });を使用する必要があります

非常に重要な違いがあります。 req.on()はこの要求にリスナーを追加し、req.connection.on()は、クライアントとサーバー間の(キープアライブ)接続にリスナーを追加します。 req.connection.on()を使用する場合、クライアントが接続を再利用するたびに、同じ接続にもう1つのリスナーを追加します。接続が最終的に中止されると、すべてのリスナーが起動されます。

関数のスコープは通常、サーバーロジックを台無しにすることからあなたを安全に保ちますが、それでもそれは危険なことです。幸い、少なくともNodeJS 0.10.26は、ユーザーに次のことを警告するのに十分なほど賢いです。

(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)
  ...
25

Node.jsに、ユーザーがリクエストを中止した(接続を閉じた)ときにイベントをチェック、検出、またはキャッチする方法はありますか?

http.ServerRequest close event を使用してみてください。簡単な例:

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
yojimbo87

Express.js(〜4.10.6)を使用していますが、次のコードが正常に機能しています。

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

ブラウザのタブを閉じるとすぐに、ブラウザは接続を閉じ、コールバック関数は期待どおりに実行されます。

3
Shivanshu Goyal

あなたの質問はこれと非常に似ているようです:

NodeJS HTTPリクエスト接続のクローズイベントが2回発生しました

試してみてください

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