可以使用卸载事件可靠地触发 ajax 请求吗?

IT技术 javascript ajax events reliability
2021-02-09 19:15:40

我需要一种方法来监视用户编辑会话,我正在审查的解决方案之一将让我使用unload事件发送 ajax 请求以通知服务器编辑会话结束。(请参阅:监控用户会话以防止编辑冲突

我对unload事件的(相当有限的)阅读表明附加到此处理程序的代码必须快速运行,因此通常用于清除对象以防止内存泄漏。

我的问题是,为此目的,这项工作是否足够可靠?

附注。我知道这个async: false选项。

5个回答

如果您的服务器足够快以进行响应,则此方法相当可靠。不过确实需要注意一些事情。如果关闭浏览器并在卸载事件时发送 AJAX 请求,则很有可能在窗口对象被销毁之前响应不会及时从服务器返回。在这种情况下(至少对于 IE)会发生什么,它将孤立您的连接对象,并且在连接超时之前不会正确终止它。如果您的服务器没有打开连接保持连接,在您关闭 2 个窗口后(同时仍然打开另一个窗口),您将耗尽与服务器的开放连接(对于 IE6-7,对于 IE8-6 窗口)在达到连接超时之前,您将无法打开您的网站。

我之前遇到过这样的情况,我打开一个在卸载时发送 AJAX 请求的弹出窗口,它非常可靠,但它被上述问题所困扰,我花了很长时间来跟踪它下来并了解发生了什么。在那之后,我所做的是确保打开的窗口将具有相同的代码来调用服务器,并且在每次卸载时检查开启器并在那里运行代码(如果存在)。

似乎如果您关闭最后一个浏览器窗口,IE 会正确破坏连接,但如果打开另一个窗口,则不会。

PS 只是为了评论上面的答案,AJAX 并不是真正的异步。至少它的 JS 实现不是。发送请求后,您的 JS 代码仍将等待服务器的响应。它不会阻止您的代码执行,但由于服务器可能需要一段时间来响应(或足够长的时间让 Windows 终止 IE 窗口对象),您可能并且可能会遇到上述问题。

没错。关闭异步后,浏览器将在卸载页面之前等待服务器的响应。这有助于解决 Chrome 错误,Chrome 在卸载事件和异步操作时非常不可靠。这也将修复我上面描述的 IE 连接占用。但它将是用户可见的。
2021-03-21 19:15:40
不推荐使用同步请求,使用 async:false 调用 ajax 将在将来停止工作。developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest搜索async
2021-03-30 19:15:40
有没有人在关闭异步的情况下尝试过这个?我猜这会阻止浏览器卸载,直到请求返回。
2021-03-31 19:15:40
值得关注新的 Beacon API Navigator.sendBeacon,它将提供一种更好的方式在卸载时可靠地向我们的服务器发出异步请求:developer.mozilla.org/en-US/docs/Web/API/Navigator/sendBeacon
2021-04-06 19:15:40
同步请求支持已从 Chrome 版本 82 中删除。
2021-04-07 19:15:40

你有没有试过使用

var i = new Image(1,1); 
i.src='http://...'

并且只是从服务器返回一些空图像。我认为它应该是可靠的,脚本会阻塞。顺便说一句:很高兴添加时间戳以防止缓存。

我发现 onload 事件函数中的 AJAX 调用不起作用,但是这个方法起作用了。需要注意的是,该功能代码不会停止或阻止页面卸载,该代码可能会在页面卸载后执行。
2021-03-26 19:15:40

我们有一个需要它的案例。这是一个报告页面,需要大量的服务器内存,所以我们想在他们离开页面后立即释放它。我们创建了一个框架集并在那里添加了卸载处理程序。最可靠的方法是将图像的 src 设置为释放脚本。我们实际上同时使用了 unload 和 onbeforeunload 来实现跨浏览器兼容性。它在 web kit nightlies 中不起作用,但管理人员对此没有意见。

然而,这不是我提出的解决方案。我会使用心跳方法,它涉及更多的工作,但更强大。

您的页面应该定期发送心跳请求。每个请求都会设置页面的最后一次心跳。然后,您需要一个在服务器上运行的线程,如果最后一次心跳时间太长,则清除内存。

这并不能解决长时间离开页面的问题。为此,您需要对用户活动进行一些监控,并在一段时间不活动后离开该页面(确保与用户确认)

我们需要框架集是因为页面内正在进行导航,我们只想在离开页面集时发送“空闲内存”请求。图像/两次卸载方法是我们让它跨浏览器和操作系统最可靠地运行的方式。
2021-03-21 19:15:40
真的需要frameset, image 和 freeing 脚本方法吗?这似乎相当骇人听闻......或者与使用这两个unload事件相比是否更可靠
2021-04-06 19:15:40

您必须自己测试您的特定场景是否在您拥有的时间内工作unload,但发出 AJAX 请求非常快,因为 AJAX 是异步的。您只需发送请求,然后就完成了!(不过,也许您必须清除刚刚创建的请求对象。)

如果您想验证 AJAX 请求是否成功,那么您必须更加担心/使用该async:false选项(如本讨论所示)。但是,只是发送是一个快速的繁荣 - 你就完成了操作。

好吧,如果它无法到达服务器,我不会称其为可靠的,对吗?;)
2021-03-25 19:15:40
是的,但我认为您的意思是可靠的,因为浏览器实际上会发送请求。
2021-04-08 19:15:40

我有一个案例,我只需要通知服务器端有关卸载的信息,而不关心响应。

如果那是你的情况,你可以ignore_user_abort然后你知道它会“可靠地”发生