web-dev-qa-db-ja.com

JavaScript、ブラウザ、ウィンドウを閉じる-AJAXリクエストを送信するか、ウィンドウを閉じるときにスクリプトを実行します

ユーザーが指定したページを離れたときを調べようとしています。彼がページ内のリンクを使用して移動したことを確認しても問題はありませんが、彼がウィンドウを閉じたときや別のURLを入力してEnterキーを押したときなどにマークアップする必要があります。 2つ目はそれほど重要ではありませんが、1つ目は重要です。だからここに質問があります:

ユーザーが自分のページを閉じたとき(ウィンドウwindow.closeイベントをキャプチャ)を確認するには、どうすればよいですか...問題はありません(AJAXリクエストを送信する必要がありますが、アラートを実行するためにそれを取得し、私は残りを行うことができます)。

29
zozo

unloadおよびbeforeunload javascriptイベントがありますが、Ajaxリクエストでは信頼できません(これらのイベントの1つで開始されたリクエストがサーバーに到達することは保証されていません)。

したがって、これを行うことを強くお勧めしますnotが推奨されます。代わりの方法を探す必要があります。

これが絶対に必要な場合は、「ping」スタイルのソリューションを検討してください。基本的にサーバーに「私はまだここにいる」と伝えるために、毎分リクエストを送信します。次に、サーバーがそのような要求を2分以上受信しない場合(待ち時間などを考慮する必要があります)、クライアントはオフラインであると見なします。


別の解決策は、unloadまたはbeforeunloadを使用してSjaxリクエスト(同期JavaScript And XML)を実行することですが、これは完全に推奨されていません。これを行うと、要求が完了するまでユーザーのブラウザーがフリーズしますが、要求が完了するまでは(要求に少し時間がかかったとしても)好まれません。

32
Felix

1)すべてのブラウザーで機能する方法を探している場合、最も安全な方法は同期AJAX=をサーバーに送信することです。これは良い方法ではありませんが、少なくともサーバーに大量のデータを送信していないこと、およびサーバーが高速であることを確認してください。

2)非同期AJAXリクエストを使用し、ignore_user_abort関数をサーバーで使用することもできます(PHPを使用している場合)。ただしignore_user_abortはサーバー構成に大きく依存します。十分にテストしてください。

3)最新のブラウザでは、AJAXリクエストを送信しないでください。新しいnavigator.sendBeaconメソッドを使用して、次のページの読み込みをブロックすることなく、非同期でサーバーにデータを送信します。ユーザーがページから移動する前にデータをサーバーに送信したいので、このメソッドをunloadで使用できますイベントハンドラ。

$(window).on('unload', function() {
    var fd = new FormData();
    fd.append('ajax_data', 22);
    navigator.sendBeacon('ajax.php', fd);
});

sendBeaconのポリフィル もあるようです。メソッドがネイティブで利用できない場合、同期AJAX=を送信することに頼っています。

モバイルデバイスの重要性:unloadイベントハンドラーがモバイルで発生することは保証されないことに注意してください。ただし、visibilitychangeイベントが発生することが保証されています。そのため、モバイルデバイスの場合、データ収集コードを少し調整する必要がある場合があります。

3つの方法すべてのコード実装については、私の ブログ記事 を参照してください。

18
Useful Angle

これは その他の答え に基づいています。

明確にするために、2018年には、ビーコンAPIがこの問題の解決策です(- ほぼすべてのブラウザー )。

ビーコンリクエストは、ページがアンロードされる前に開始され、ブロッキングリクエストを必要とせずに完了するまで実行されることが保証されています。

onunloadイベント内で使用でき、確実に送信されます。

$(window).on('unload', function() {

    var URL = "https://example.com/foo";
    var data = "bar";

    navigator.sendBeacon(URL, data);

});

素晴らしいブログ投稿: http://usefulangle.com/post/62/javascript-send-data-to-server-on-page-exit-reload-redirect

ビーコンAPI: https://developer.mozilla.org/en-US/docs/Web/API/Beacon_API/Using_the_Beacon_API

16
Baishu

私も同じ機能を実現したいと思っていて、Felix(からこの回答に出会いました。これらのイベントの1つで開始されたリクエストがサーバーに到達することは保証されていません)。

リクエストをサーバーに到達させるために、以下のコードを試しました:-

onbeforeunload = function() {

    //Your code goes here.

    return "";
} 

IEブラウザを使用しており、ユーザーがブラウザを閉じると、return "";のために確認ダイアログが表示され、ユーザーの確認を待機します。この待機時間がサーバーへのリクエストを行います。

3
Pradeep Yadav

これを試してみてください。私はこの問題をJavaScriptで解決し、ブラウズまたはタブを閉じるときにサーバーにajax呼び出しを送信しました。 onbeforeunload関数にページの更新を含むため、ページの更新に問題がありました。 performance.navigation.type == 1は、更新を(mozzilaブラウザーで)終了から分離する必要があります。

$(window).bind('mouseover', (function () { // detecting DOM elements
    window.onbeforeunload = null;
}));

$(window).bind('mouseout', (function () { //Detecting event out of DOM
      window.onbeforeunload = ConfirmLeave;
}));

function ConfirmLeave() {
   if (performance.navigation.type == 1) { //detecting refresh page(doesnt work on every browser)
   }
   else {
       logOutUser();
   }
}

$(document).bind('keydown', function (e) { //detecting alt+F4 closing
    if (e.altKey && e.keyCode == 115) {
        logOutUser();
    }    
});
function logOutUser() {
   $.ajax({
     type: "POST",
     url: GWA("LogIn/ForcedClosing"), //example controller/method
     async: false
   });
}
0
Stidljivi

質問を投稿してから数年後、nodejsとsocket.io( https://socket.io )を含むより優れた実装を作成しました(そのためにどのような種類のソケットでも使用できますが、それは私の個人的な選択でした) )。

基本的に私はクライアントとの接続を開き、電話が切れたらデータを保存するだけです/必要なことは何でもします。明らかに、これは何かを表示したり、クライアントをリダイレクトしたりするために使用することはできません(サーバー側で実行しているため)。

 io.on('connection', function(socket){
      socket.on('disconnect', function(){
          // Do stuff here
      });
 });

だから...最近では、これは(ノードやソケットなどが必要なため実装が難しいですが、それほど難しくはありません。最初に実行する場合は30分程度かかるはずです)よりも良い方法だと思います。アンロードバージョン。

0
zozo

選択した答えは正しいですが、ブラウザーがxhr要求を送信することを保証することはできませんが、ブラウザーによっては、タブまたはウィンドウを閉じるときに確実に要求を送信できます。

通常、ブラウザーはxhr.send()が実際に実行される前に閉じます。 ChromeおよびEdgeは、ウィンドウを閉じる前にJavaScriptイベントループが空になるのを待つように見えます。また、JavaScriptイベントループとは別のスレッドでxhrリクエストを起動します。これは、イベントループを十分に長く維持すると、xhrは正常に起動します。たとえば、xhrリクエストの送信をテストしてから100,000,000までカウントしました。これは、chromeとEdge for meの両方で非常に一貫して機能しました。angularjsを使用している場合、$ httpへの呼び出しを$ applyでラップすると、同じことが実現します。

IEは少し異なるようです。 IEはイベントループが空になるまで、または現在のスタックフレームが空になるまで待機します。時々正しくリクエストを送信しますが、はるかに頻繁に発生するようです(時間の80%〜90%)は、IEはxhrリクエストが完全に実行される前にウィンドウまたはタブを閉じ、その結果メッセージの一部のみが送信されることになります。基本的にサーバーはリクエストを投稿しますが、本文はありません。

後世のために、ここにwindow.onbeforeunloadリスナー関数として添付したコードを示します。

  var xhr = new XMLHttpRequest();
  xhr.open("POST", <your url here>);
  xhr.setRequestHeader("Content-Type", "application/json;charset=UTF-8");
  var payload = {id: "123456789"};
  xhr.send(JSON.stringify(payload));

  for(var i = 0; i < 100000000; i++) {}

私はテストしました:

Chrome 61.0.3163.100

IE 11.608.15063.0CO

エッジ40.15063.0.0

0
codepuzzler