【问题标题】:window.onbeforeunload ajax request in ChromeChrome 中的 window.onbeforeunload ajax 请求
【发布时间】:2011-06-24 04:11:01
【问题描述】:

我有一个通过 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 实现?我正在做的事情在我看来完全合法。

谢谢,

【问题讨论】:

  • “bas_send_request”函数在哪里?
  • Pointy:bas_send_request() 是一个简单的包装器,它创建一个 ajax 请求并发送它。我认为没有必要展示那种细节。

标签: javascript ajax google-chrome


【解决方案1】:

这与较新版本的 Chrome 相关。

与@Garry English said 一样,在页面onunload 期间发送async 请求将不起作用,因为浏览器会在发送请求之前终止线程。不过发送sync 请求应该可以。

这在 Chrome 29 之前是正确的,但在 Chrome V 30 上它突然停止工作as stated here

目前看来,这样做的唯一方法是使用onbeforeunload 事件as suggested here

但请注意:其他浏览器根本不允许您在 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();
});

【讨论】:

  • @Sebas,如果您可以提供更多详细信息,也许我们可以尝试提供帮助。究竟是什么失败了?它被称为 ata all 吗?你确定你的请求是同步的吗?
  • @Mohoch,它突然停止工作。我怀疑新版本的 chrome 会造成问题,但在我意识到更多测试之前我无法确定。我正在使用一个框架,有一个布尔值可以将 ajax 调用设置为同步,并且它在整个软件中运行良好,除了窗口的 onbeforeunload 事件。 (引发网络错误)
  • @AitazazKhan,答案本身有一个示例,同时使用 onunload 和 onbeforeunload。您还可以查看this page 以获得更多解释和示例。如果我在您的问题中遗漏了什么,请随时详细说明,以便我查明确切的问题。
  • 太棒了。你可以直接写 ... .on('unload beforeunload', ... 直接把函数打包进去,不是吗?
  • chrome 80 及更高版本不支持此功能。我刚刚遇到一个问题并降落在这里。 developers.google.com/web/updates/2019/12/chrome-80-deps-rems
【解决方案2】:

我遇到了同样的问题,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 中适用于我。

【讨论】:

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

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

MDN 页面说:

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

此方法可满足分析和诊断代码的需求 通常尝试在卸载之前将数据发送到 Web 服务器 的文件。过早发送数据可能会导致错过 收集数据的机会。但是,确保数据已 在卸载文档期间发送的内容 传统上对开发人员来说很困难。

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

【讨论】:

  • 请注意,一些广告拦截器(如 uBlock Origin)出于某种跟踪预防的目的而阻止 Navigator.sendBeacon。因此,您的应用根本无法依赖它。
【解决方案4】:

同步 XMLHttpRequest 已被弃用 (Synchronous and asynchronous requests)。因此,jQuery.ajax()async: false 选项也已被弃用。

beforeunloadunload 期间使用同步请求似乎不可能(或非常困难) (Ajax Synchronous Request Failing in Chrome)。所以推荐使用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);
});

【讨论】:

  • 你的意思是在窗口卸载期间同步和异步请求都被弃用了吗?
  • @surajnaik Synchronous XMLHttpRequest 一般,我猜。
【解决方案5】:

尝试创建一个变量(最好是布尔变量)并在您从 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;
}

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

【讨论】:

  • 感谢您的回复。这看起来值得一试。但是我设法找到了另一个不需要客户端断开连接的解决方案。还是谢谢你。
【解决方案6】:

当用户离开页面并向后端发送 ajax 请求时,我必须跟踪任何情况。

var onLeavePage = function() {
    $.ajax({
        type: 'GET',
        async: false,
        data: {val1: 11, val2: 22},
        url: backend_url
    });
};

/**
 * Track user action: click url on page; close browser tab; click back/forward buttons in browser
 */
var is_mobile_or_tablet_device = some_function_to_detect();
var event_name_leave_page = (is_mobile_or_tablet_device) ? 'pagehide' : 'beforeunload';
window.addEventListener(event_name_leave_page, onLeavePage);

/**
 * Track user action when browser tab leave focus: click url on page with target="_blank"; user open new tab in browser; blur browser window etc.
 */
(/*@cc_on!@*/false) ?  // check for Internet Explorer
    document.onfocusout = onLeavePage :
    window.onblur = onLeavePage;

请注意,桌面浏览器中会触发事件“pagehide”,但当用户单击浏览器中的后退/前进按钮时它不会触发(在最新的当前版本的 Mozilla Firefox 中测试)。

【讨论】:

    【解决方案7】:
    Try navigator.sendBeacon(...);
    
    try {
            // For Chrome, FF and Edge
            navigator.sendBeacon(url, JSON.stringify(data));
        }
        catch (error)
        {
            console.log(error);
        }
    
        //For IE
        var ua = window.navigator.userAgent;
        var isIEBrowser = /MSIE|Trident/.test(ua);
    
        if (isIEBrowser) {
            $.ajax({
                url: url,
                type: 'Post',
                .
                .
                .
            });
        }
    

    【讨论】:

    • 请不要只发布代码作为答案,还要解释您的代码的作用以及它如何解决问题的问题。带有解释的答案通常更有帮助、质量更好,并且更有可能吸引投票。
    • 感谢您发布此内容!
    【解决方案8】:

    我一直在寻找一种通过 AJAX 请求检测离开页面的方法。它就像我每次使用它时一样工作,并用 MySQL 检查它。这是代码(在 Google Chrome 中工作):

        $(window).on("beforeunload", function () {
            $.ajax({
                 type: 'POST',
                 url: 'Cierre_unload.php',
                 success: function () {
                 }
            })
        })
    

    【讨论】:

      猜你喜欢
      • 2018-09-07
      • 2019-07-27
      • 2014-02-14
      • 1970-01-01
      • 2019-09-04
      • 2016-10-15
      • 1970-01-01
      相关资源
      最近更新 更多