JavaScript, navegadores, fechamento de janela – envie uma solicitação AJAX ou execute um script no fechamento da janela

Estou tentando descobrir quando um usuário deixou uma página especificada. Não há problema em descobrir quando ele usou um link dentro da página para navegar, mas eu meio que preciso marcar algo como quando ele fechou a janela ou digitou outra URL e pressionou enter. O segundo não é tão importante, mas o primeiro é. Então aqui está a questão:

Como posso ver quando um usuário fechou minha página (evento capture window.close), e então … realmente não importa (eu preciso enviar uma solicitação AJAX, mas se eu conseguir que ele execute um alerta, eu posso Faça o resto).

Há events javascript unload e beforeunload , mas eles não são confiáveis ​​para uma solicitação Ajax (não é garantido que uma solicitação iniciada em um desses events atinja o servidor).

Portanto, isso não é recomendado, e você deve procurar uma alternativa.

Se você definitivamente precisa disso, considere uma solução de estilo “ping”. Envie uma solicitação a cada minuto, basicamente dizendo ao servidor “Eu ainda estou aqui”. Então, se o servidor não receber tal solicitação por mais de dois minutos (você precisa levar em conta latências, etc.), você considera o cliente offline.


Outra solução seria usar unload ou beforeunload para fazer uma solicitação Sjax (Synchronous JavaScript And XML), mas isso não é totalmente recomendado. Fazer isso basicamente congelará o navegador do usuário até que a solicitação seja concluída, o que eles não vão gostar (mesmo que a solicitação leve pouco tempo).

1) Se você está procurando uma maneira de trabalhar em todos os navegadores, a maneira mais segura é enviar um AJAX síncrono para o servidor. Não é um bom método, mas pelo menos certifique-se de não enviar muitos dados para o servidor, e o servidor é rápido.

2) Você também pode usar uma solicitação AJAX assíncrona e usar a function ignore_user_abort no servidor (se estiver usando PHP). No entanto ignore_user_abort depende muito da configuração do servidor. Certifique-se de testá-lo bem.

3) Para navegadores modernos, você não deve enviar uma solicitação AJAX. Você deve usar o novo método navigator.sendBeacon para enviar dados ao servidor de forma assíncrona e sem bloquear o carregamento da próxima página. Como você está querendo enviar dados para o servidor antes que o usuário saia da página, você pode usar esse método em um manipulador de events unload .

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

Também parece haver um polyfill para sendBeacon . Recorre ao envio de um AJAX síncrono se o método não estiver disponível nativamente.

IMPORTANTE PARA DISPOSITIVOS MÓVEIS: Observe que não é garantido que o manipulador de events descarregar seja triggersdo para celulares . Mas o evento visibilitychange é garantido para ser triggersdo. Portanto, para dispositivos móveis, seu código de coleta de dados pode precisar de alguns ajustes.

Você pode consultar o artigo do meu blog para a implementação do código de todas as três formas.

Eu também queria alcançar a mesma funcionalidade e me deparei com essa resposta da Felix ( não é garantido que uma solicitação iniciada em um desses events chegue ao servidor ).

Para fazer o pedido chegar ao servidor, tentamos abaixo do código: –

 onbeforeunload = function() { //Your code goes here. return ""; } 

Estamos usando o navegador IE e agora quando o usuário fecha o navegador, ele recebe o diálogo de confirmação por causa do return ""; e aguarda a confirmação do usuário e esse tempo de espera faz com que a solicitação chegue ao servidor.

Baseando isso na outra resposta .

Para esclarecer as coisas, em 2018, a API Beacon é a solução para esse problema (em quase todos os navegadores )

É garantido que as Solicitações de Beacon sejam iniciadas antes que uma página seja descarregada e sejam executadas até a conclusão, sem exigir uma solicitação de bloqueio.

Você pode usá-lo em onunload evento onunload e ter certeza de que ele será enviado.

 $(window).on('unload', function() { var URL = "https://example.com/foo"; var data = "bar"; navigator.sendBeacon(URL, data); }); 

Ótimo post no blog: http://usefulangle.com/post/62/javascript-send-data-to-server-on-page-exit-reload-redirect

API do Beacon: https://developer.mozilla.org/pt-BR/docs/Web/API/Beacon_API/Using_the_Beacon_API

Estou de acordo com a idéia da Felix e resolvi meu problema com essa solução e agora quero limpar a solução do lado do servidor:

1. enviar uma solicitação do lado do cliente para o servidor

Tempo de salvamento do último pedido recebido em uma variável

3. Verifique o horário do servidor e compare-o pela variável da última solicitação recebida

4. Se o resultado for maior que o tempo esperado, comece a executar o código que deseja executar quando o Windows for fechado …

A resposta selecionada está correta: você não pode garantir que o navegador envie a solicitação xhr, mas, dependendo do navegador, você pode enviar uma solicitação com segurança na guia ou no fechamento da janela.

Normalmente, o navegador fecha antes que xhr.send () seja realmente executado. O Chrome e o Edge parecem esperar que o loop de events do JavaScript seja esvaziado antes de fechar a janela. Eles também triggersm a solicitação xhr em um thread diferente do loop de events do javascript. Isso significa que se você puder manter o loop de events cheio por tempo suficiente, o xhr será acionado com sucesso. Por exemplo, testei o envio de uma solicitação xhr e, em seguida, contei até 100.000.000. Isso funcionou muito consistentemente em ambos os cromo e borda para mim. Se você estiver usando angularjs, encapsular sua chamada para $ http em $ apply faz a mesma coisa.

IE parece ser um pouco diferente. Eu não acho que o IE aguarda o loop de events para esvaziar, ou até mesmo para o quadro de pilha atual para vazio. Embora ocasionalmente envie uma solicitação corretamente, o que parece acontecer com muito mais frequência (80% -90% do tempo) é que o IE fechará a janela ou a guia antes que a solicitação xhr seja completamente executada, o que resulta em apenas uma mensagem parcial sendo enviado. Basicamente, o servidor recebe uma solicitação de postagem, mas não há corpo.

Para a posteridade, aqui está o código que usei anexado como a function window.onbeforeunload ouvinte:

  var xhr = new XMLHttpRequest(); xhr.open("POST", ); 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++) {} 

Eu testei em:

Chrome 61.0.3163.100

IE 11.608.15063.0CO

Edge 40.15063.0.0

Usar:

  

Deve capturar tudo, exceto desligar o programa do navegador.