卸载事件处理程序中关闭Chrome窗口未发送数据使用sendBeacon

7

我正在尝试在窗口关闭时发送数据,以防止两个人同时编辑并覆盖对方的数据。目前,我在卸载事件处理程序中使用了sendBeacon。

FireFox:

  • 刷新:可行
  • 返回按钮:可行
  • 关闭窗口:可行

Chrome:

  • 刷新:可行
  • 返回按钮:可行
  • 关闭窗口:不可行

这是我的代码:

function sendDataOnClose(edit,trans){

    var url = "../../save.php"; //This has a post request handler and works properly with other functions for saving data

    const data = JSON.stringify
    ({
      "translations": trans,
      "edit": edit
    });

    navigator.sendBeacon(url, data);
  }

function handleClose(){
    if(edit){
      console.log("sending a false when edit is: "+ edit)
      sendDataOnClose(false, translations);
    }
  }

window.addEventListener('unload', handleClose); 

尽管文档显示“unload和beforeunload事件不适合与sendBeacon一起使用。相反,请使用visibilitychange。”,但在关闭时使用visibilitychange事件仍然无效! - Brackets
1
它在所有主要浏览器的最新版本上都能正常工作,我最近进行了测试。您可以查看此帖子:https://stackoverflow.com/a/69955104/1786360 此外,请尝试将 window.addEventListener('unload', handleClose); 替换为 'beforeUnload' 事件,这在 Chrome 浏览器中似乎正常工作。对于您来说,这不应该有任何区别。相信我,它在 timeonsite JS 跟踪器中被广泛使用,并且在大量桌面浏览器和移动设备上(不包括 IOS 设备)表现出高度的可靠性和前途。 - webblover
2个回答

1
最新的MDN关于sendBeacon的文档说明:“navigator.sendBeacon()方法异步地向Web服务器发送少量数据。它旨在与visibilitychange事件一起使用(但不是unload和beforeunload事件)。”
如建议一样使用visibilitychange事件,您可以:
document.addEventListener('visibilitychange', function() {
  if (document.visibilityState === 'hidden') {
    navigator.sendBeacon(handleClose);
  }
});

我曾经遇到过类似的问题,试图在“unload”事件上发送数据。用户群体都在桌面端吗?移动设备不能可靠地触发“unload”事件。页面生命周期API提供了可见性更改事件和“pagehide”事件,可以一起使用以更接近您想要的结果。

页面生命周期API尝试通过: 引入和标准化Web上的生命周期状态的概念。 定义新的、系统启动的状态,允许浏览器限制被隐藏或不活动选项卡消耗的资源。 创建新的API和事件,允许Web开发人员对这些新的系统启动状态的转换作出响应。 来源

您遇到的问题很可能更多地涉及浏览器如何暂停页面或完全丢弃页面的问题。不幸的是,浏览器在如何处理此问题上并不统一,而且在桌面端和移动端上有不同的行为。
如果您感兴趣的话,有几个线程更深入地讨论了这个问题。在浏览器标准化之前,我不确定是否有一个简单的答案,比如"use x event"。
问题:页面可见性问题提出。
关于sendBeacon的MDN strints上的问题

pagehidevisbilitychange在标签页关闭时都不会触发。这就是问题所在。我需要任何在窗口关闭时触发的事件,但没有一个起作用。 - Brackets
1
请将其拼写为“visibility”,而不是“visbility”。 - Janos Vinceller

0

多亏了黑客,出于安全原因,许多其他东西都被删除了。

我注意到你的问题也有PHP标签;我会给你一个不好的想法,但是一个功能性的想法。避免使用on-close-page handles,即使是JavaScript或框架,只需使用JavaScript将表数据库发布到您存储time()和目标ID,然后如果超时可能超过30秒,则将其从表中删除,您将知道该页面仍未工作(翻译:使用服务器“在线用户”想法(像任何应用程序一样产生大量流量的必要但不好的想法)。

在客户端侧使用这些JavaScript是个坏主意,你会为那些利用你的应用程序的坏人打开大门。


我已经在服务器端设置了超时,现在我想在用户关闭页面时结束计时器。 - Brackets
1
@Brackets比较简单!超时应该自动过期。每当用户目标或另一个用户进入时,脚本启动时应检查所有超时并删除它们。缺失的是目标开始时间,因此您可以通过验证开始和停止与当前PHP时间引用来处理服务器上的关闭页面和超时。根据超时差异。 - user5781320
请编辑答案以包含这个想法。 - Janos Vinceller
1
@Janos Vinceller 我可以编写一个PHP MySQL脚本来演示“在线用户”开始然后停止PHP验证程序处理程序,但不会完全符合我心中的想法(在我的情况下,这些情况代码在我需要之前就已经存在于我的框架中,所以我不会在stackoverflow上查找我已经知道的答案)。关于防止黑客攻击的部分,我将不再发布任何可能给同行提供想法的内容,我尝试在我的应用程序内部停止它。所以如果您不喜欢这个答案,我可以删除它。 - user5781320

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接