JavaScript,浏览器,窗口关闭 – 发送AJAX请求或在窗口关闭时运行脚本

我试图找出用户何时离开指定页面。 当他使用页面内的链接导航时,没有任何问题,但我需要标记的东西,如他关闭窗口或键入另一个URL并按回车。 第二个不是那么重要,但是第一个是。 所以这里是一个问题:

我怎样才能看到当用户关闭我的网页(捕获window.close事件),然后…并不重要(我需要发送一个AJAX请求,但如果我能得到它运行一个警报,我可以做其余的)。

unloadbeforeunload JavaScript事件,但这些是不可靠的Ajax请求(不保证在这些事件之一发起的请求将到达服务器)。

因此,这样做是非常推荐的,你应该寻找替代品。

如果你确实需要这个,可以考虑一个“ping”风格的解决方案。 每分钟发一个请求,基本上告诉服务器“我还在这里”。 然后,如果服务器没有收到超过两分钟的请求(您必须考虑延迟等),则认为客户端处于脱机状态。


另一种解决方案是使用unloadbeforeunload做一个Sjax请求(同步JavaScript和XML),但是这完全不被推荐。 这样做基本上会冻结用户的浏览器,直到请求完成,他们不会喜欢(即使请求花费很少的时间)。

我也想实现相同的功能,从Felix中得到这个答案( 不保证在这些事件之一发起的请求将到达服务器 )。

为了使请求到达服务器,我们尝试下面的代码:

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

我们使用IE浏览器&现在当用户关闭浏览器,然后他得到确认对话,因为return ""; 等待用户的确认和这个等待时间使请求到达服务器。

林同意费利克斯的想法,我已经解决了我的问题,该解决方案,现在我想清除服务器端解决方案:

1.发送客户端到服务器的请求

保存最后一个请求的时间在一个变量中

3.检查服务器时间,并将其与上次收到的请求的变量进行比较

如果结果超出了你的期望,开始运行你想在Windows关闭时运行的代码。

所选的答案是正确的,你不能保证浏览器发送的xhr请求,但根据浏览器,你可以可靠地发送请求选项卡或窗口关闭。

通常,浏览器在xhr.send()实际执行之前关闭。 铬和边缘看起来像他们在关闭窗口之前等待JavaScript事件循环清空。 他们还在不同于javascript事件循环的线程中激发xhr请求。 这意味着如果你可以将事件循环保持足够长的时间,xhr将会成功的开火。 例如,我测试了发送一个xhr请求,然后数到100,000,000。 对于我来说,这在铬和边缘都非常一致。 如果您使用的是angularjs,则在$ apply中将您的调用包装到$ http中即可完成相同的操作。

IE似乎有点不同。 我不认为IE等待事件循环清空,甚至是当前的栈帧清空。 虽然它偶尔会正确地发送一个请求,但似乎更常发生的事情(80%-90%的时间)是IE会在xhr请求完全执行之前关闭窗口或标签,这只会导致部分消息正在发送。 基本上服务器收到一个post请求,但没有任何内容。

对于后人,下面是我用作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

1)如果您正在寻找一种在所有浏览器中工作的方法,那么最安全的方法是将同步AJAX发送到服务器。 这不是一个好的方法,但至少要确保你没有向服务器发送太多的数据,而且服务器速度很快。

2)您也可以使用异步AJAX请求,并在服务器上使用ignore_user_abort函数(如果您使用的是PHP)。 然而, ignore_user_abort依赖于服务器配置。 确保你测试得好。

3)对于现代浏览器,你不应该发送一个AJAX请求。 您应该使用新的navigator.sendBeacon方法异步发送数据到服务器,而不会阻塞下一页的加载。 由于您希望在用户移出页面之前将数据发送到服务器,因此可以在卸载事件处理程序中使用此方法。

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

似乎还有一个用于sendBeacon的polyfill 。 它假设发送一个同步AJAX如果方法不是本地可用的。

移动设备的重要事项: 请注意, 卸载事件处理程序不保证被解雇的手机 。 但visiblechange事件保证被解雇。 因此,对于移动设备,您的数据收集代码可能需要一些调整。

您可以参考我的博客文章 ,了解所有3种方法的代码实现。

使用:

 <body onUnload="javascript:"> 

除了关闭浏览器程序之外,它应该捕获所有内容。