Chrome 中的 window.onbeforeunload ajax 请求

Posted

技术标签:

【中文标题】Chrome 中的 window.onbeforeunload ajax 请求【英文标题】:window.onbeforeunload ajax request in Chrome 【发布时间】: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 请求并发送它。我认为没有必要展示那种细节。 【参考方案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 () 
             
        )
    )

【讨论】:

以上是关于Chrome 中的 window.onbeforeunload ajax 请求的主要内容,如果未能解决你的问题,请参考以下文章

Chrome扩展开发之三——Chrome扩展中的数据本地存储和下载

chrome中的Chrome css3混合混合模式错误

怎样使chrome开发者工具中的response显示成json格式

Chrome 中的本机延迟加载

Chrome 调试器分析器中的“(程序)”是啥?

Chrome 中的 $ 变量(美元符号)?