Chrome 中的 window.onbeforeunload ajax 请求

IT技术 javascript ajax google-chrome
2021-01-23 17:28:30

我有一个通过 Ajax 处理机器远程控制的网页。当用户离开页面时,我想自动断开与机器的连接。所以这里是代码:

window.onbeforeunload = function () {
  bas_disconnect_only();
}

断开连接函数只是向 PHP 服务器端脚本发送一个 HTTP GET 请求,它完成断开连接的实际工作:

function bas_disconnect_only () {
   var xhr = bas_send_request("req=10", function () {
   });
}

这在 FireFox 中运行良好。但是对于 Chrome,根本不发送 ajax 请求。有一个不可接受的解决方法:向回调函数添加警报:

function bas_disconnect_only () {
   var xhr = bas_send_request("req=10", function () {
     alert("You're been automatically disconnected.");
   });
}

添加警报调用后,请求将成功发送。但正如你所看到的,这根本不是一个解决办法。

有人能告诉我这是否可以用 Chrome 实现?我正在做的事情在我看来完全合法。

谢谢,

6个回答

这与较新版本的 Chrome 相关。

就像@Garry English说的那样async在页面期间发送请求是onunload行不通的,因为浏览器会在发送请求之前杀死线程。发送sync请求应该可以工作。

这一直到 Chrome 29 版,但在 Chrome V 30 上它突然停止工作,如此处所述

看来今天这样做的唯一方法是使用此处建议onbeforeunload事件

但请注意:其他浏览器根本不会让您在 onbeforeunload 事件中发送 Ajax 请求。所以你需要做的是在卸载和卸载之前执行操作,并检查它是否已经发生。

像这样的东西:

var _wasPageCleanedUp = false;
function pageCleanup()
{
    if (!_wasPageCleanedUp)
    {
        $.ajax({
            type: 'GET',
            async: false,
            url: 'SomeUrl.com/PageCleanup?id=123',
            success: function ()
            {
                _wasPageCleanedUp = true;
            }
        });
    }
}


$(window).on('beforeunload', function ()
{
    //this will work only for Chrome
    pageCleanup();
});

$(window).on("unload", function ()
{
    //this will work for other browsers
    pageCleanup();
});
@Mohoch,它突然停止工作。我怀疑是新版本的 chrome 造成了这个问题,但在我意识到更多测试之前我无法确定。我正在使用一个框架,有一个布尔值可以将 ajax 调用设置为同步,它在整个软件中都运行良好,除了窗口的 onbeforeunload 事件。(引发网络错误)
2021-03-20 17:28:30
@Sebas,如果您能提供更多详细信息,也许我们可以尝试提供帮助。究竟是什么失败了?是不是都叫ata?你确定你的请求是同步的吗?
2021-03-22 17:28:30
伟大的。你可以只写 ... .on('unload beforeunload', ... 然后直接在那里打包函数,不是吗?
2021-03-29 17:28:30
@AitazazKhan,答案本身有一个例子,同时使用 onunload 和 onbeforeunload。您还可以查看此页面以获取更多解释和示例。如果我在您的问题中遗漏了某些内容,请随时详细说明,以便我可以查明确切的问题。
2021-03-31 17:28:30
这在 chrome 80 及更高版本上不受支持。我刚刚遇到了一个问题并降落在这里。developer.google.com/web/updates/2019/12/chrome-80-deps-rems
2021-04-10 17:28:30

我遇到了同样的问题,Chrome 没有在 window.unload 事件中向服务器发送 AJAX 请求。

如果请求是同步的,我只能让它工作。我能够使用 Jquery 做到这一点并将async属性设置false

$(window).unload(function () {
   $.ajax({
     type: 'GET',
     async: false,
     url: 'SomeUrl.com?id=123'
   });
});

上面的代码在 IE9、Chrome 19.0.1084.52 m 和 Firefox 12 中对我有用。

请注意,不推荐使用同步 ajax 调用。IIRC,现代浏览器在执行同步 ajax 时会在控制台中显示警告。
2021-03-13 17:28:30
该解决方案不起作用。它只是偶尔工作一次。
2021-03-20 17:28:30
async: false自 jQuery 1.8 ( api.jquery.com/jQuery.ajax )起已被弃用
2021-03-20 17:28:30
请阅读下面@Mohoch 给出的更新答案。它提供了反映浏览器更改的更新答案。
2021-04-07 17:28:30
在页面关闭期间应删除同步 XHR 调用。它将在 Chrome 80 中删除。chromestatus.com/feature/4664843055398912
2021-04-11 17:28:30

检查为此目的构建Navigator.sendBeacon()方法。

MDN 页面说:

navigator.sendBeacon() 方法可用于将小型 HTTP 数据从用户代理异步传输到 Web 服务器。

此方法解决了分析和诊断代码的需求,这些代码通常会在卸载文档之前尝试将数据发送到 Web 服务器。过早发送数据可能会导致错失收集数据的机会。但是,确保在卸载文档期间发送数据对于开发人员来说历来是困难的。

这是一个相对较新的 API,IE 似乎还不支持。

请注意,一些广告拦截器(如 uBlock Origin)出于某种跟踪预防的目的而阻止 Navigator.sendBeacon。因此,您的应用根本无法依赖它。
2021-03-25 17:28:30

同步XMLHttpRequest已被弃用(同步和异步请求)。因此,jQuery.ajax()async: false选项也已被弃用。

beforeunloadunloadChrome 中的 Ajax 同步请求失败期间使用同步请求似乎是不可能的(或非常困难的)。所以推荐使用sendBeacon,我绝对同意!

简单地:

window.addEventListener('beforeunload', function (event) {  // or 'unload'
    navigator.sendBeacon(URL, JSON.stringify({...}));

    // more safely (optional...?)
    var until = new Date().getTime() + 1000;
    while (new Date().getTime() < until);
});
您的意思是在窗口卸载期间不推荐使用同步和异步请求吗?
2021-03-19 17:28:30
@surajnaikXMLHttpRequest一般是同步的,我猜。
2021-03-21 17:28:30

尝试创建一个变量(最好是布尔值)并在收到 Ajax 调用的响应后更改它。并将该bas_disconnect_only()函数放入一个 while 循环中。我也遇到过这样的问题。我认为这是因为 Chrome 不等待 Ajax 调用。我不知道我是如何修复它的,我还没有尝试过这段代码,所以我不知道它是否有效。这是一个例子:

var has_disconnected = false;
window.onbeforeunload = function () {
    while (!has_disconnected) {
        bas_disconnect_only();
        // This doesn't have to be here but it doesn't hurt to add it:
        return true;
    }
}

bas_send_request()函数内部xmlhttp是 HTTP 请求):

xmlhttp.onreadystatechange = function() {
    if (xmlhttp.readyState == 4 && xmlhttp.status == 200)
        has_disconnected = true;
}

祝你好运,我希望这会有所帮助。

谢谢回复。看起来值得一试。但是我设法找到了另一种不需要客户端断开连接的解决方案。谢谢都一样。
2021-04-01 17:28:30