【问题标题】:Send information about clicked link to the server before redirect在重定向之前将有关单击的链接的信息发送到服务器
【发布时间】:2019-08-30 00:38:51
【问题描述】:

我们正在创建一个用于构建热图的点击跟踪应用。我正在编写一个脚本,用户应该将其插入到他们的页面中以进行跟踪。

它适用于不需要重定向或表单提交的元素。例如,如果我点击h1p 或其他任何东西,它会完全正确。但是,如果我点击a,对我们服务器的请求永远不会在正常重定向之前发生。

在过去的几天里,我尝试了很多方法来做到这一点。首先,我尝试了一个普通的 AJAX 调用,因为它是一个跨域请求,我必须使用 JSONP,但同样,该 AJAX 调用在重定向之前没有时间执行。添加async: false 可以解决问题,但它不适用于 JSONP 请求。所以我决定添加一个标志变量,表明可以安全地继续使用重定向,并使用一个空的while循环等待它在ajax回调中变为try。但是 while 循环阻塞了执行流程,所以回调永远没有机会将该变量设置为true。这是一些简化的代码:

$(document).on('click', function (e) {
    //part of the code is omitted 
    $.ajax({
        url: baseUrl,
        data: data,
        type: "get",
        dataType: "jsonp",
        crossDomain: true,
        complete: function (xhr, status,) {
            itsSafeToMoveOn = true;
        }
    });

    while(!itsSafeToMoveOn){}

    return true;
});

接下来我尝试使用 unload 页面事件来等待正在进行的 ajax 调用总数变为零(我实现了一个计数器),然后继续进行重定向。它在 Firefox 和 IE 中工作,但在 WebKit 中出现此错误:

Error: Too much time spent in unload handler

在那之后,我意识到我不关心服务器响应,并且使用img.src 请求将非常适合这种情况。所以此时代码如下所示:

$(document).click(function (e) {
    //part of the code is ommited
    (new Image).src = baseUrl + '?' + data;

    if (tag === "a" || clickedElement.parents().has("a")) {
        sleep(100); 
    }

    return true;
});

这样我稍微提高了整体脚本性能,但链接问题保持不变。 sleep 函数似乎也阻塞了执行流程,请求永远不会发生。

剩下的唯一想法是从事件处理程序返回false,然后手动重定向到单击元素的href 或在表单上调用submit(),但这会使事情复杂化,相信我已经在不同的浏览器中调试此脚本非常痛苦。

还有人有其他想法吗?

【问题讨论】:

  • 你试过 preventDefault 吗?
  • 你的itsSafeToMoveOn var 声明在哪里?
  • @JibiAbraham 我需要重定向,preventDefault 会取消它。
  • @sp00m 它是在该点击处理程序中声明的

标签: javascript jquery


【解决方案1】:
var globalStopper = true;

$(document).on('click', function (e) {
    if (globalStopper === false)
        return true; //proceed with click if stopper is NOT set
    else {
        globalStopper = false; //release the breaks

        $.ajax({
            //blahblah
            complete: function (xhr, status,) {
                $(elem).click(); //when ajax request done - "rerun" the click
            }
        });
        return false; //DO NOT let browser process the click
    }
});

另外,不要添加图像,而是尝试添加脚本。然后将脚本添加到 HEAD 部分。这样浏览器将“等待”直到它被加载。

 $(document).on('click', function (e) {
     var scriptTag = document.createElement("script");
     scriptTag.setAttribute("type", "text/javascript");
     scriptTag.setAttribute("src", url);
     document.getElementsByTagName("head")[0].appendChild(scriptTag);
     return true;
 }

【讨论】:

    【解决方案2】:

    我会看一下this stack overflow answer 中提到的或直接链接到here 的导航器 sendBeacon API。

    来自网站上的描述

    navigator.sendBeacon(url, data) - 此方法满足分析和诊断代码的需求,这些代码通常会在卸载文档之前尝试将数据发送到 Web 服务器。

    【讨论】:

      【解决方案3】:

      您可以将信息保存到 ajax 请求中的 cookie 或 localStorage 中,并让任何将发送信息的工作人员。保存到 cookie 或 localStorage 比 ajax-request 更快。接下来你可以做:

      $(document).click(function (e) {
          var queue = localStorage.getItem('requestQueue');
          queue.push(data);
          localStorage.setItem('requestQueue',queue);
      });
      
      $(function(){
        setInterval(function(){
          var queue = localStorage.getItem('requestQueue');
          while (queue.length > 0) {
            var data = queue.pop();
            $.ajax({
              ...
              success: function(){
                localStorage.setItem('requestQueue', queue);
              }
            });
          }
        },intervalToSendData);
      });
      

      因此,当用户单击链接或发送表单时,数据将被保存到存储中,并且在用户转到下一页后,此工作器将启动并将数据发送到您的服务器。

      【讨论】:

      • 我也有这个想法。这有点像是我的后备计划,但很有可能下一页上不会有我的脚本,所以那些缓存的请求将永远保留在 cookie 中。
      • 如果下一页在另一个网站上怎么办??
      【解决方案4】:

      JavaScript 基本上是在单线程中执行的。不可能让你的回调函数执行,同时有一个无限循环等待它的标志变量。无限循环会占用单个执行线程,永远不会调用回调。

      最好的方法是取消您的事件的默认处理程序并为它冒泡(如果您真的使用 jQuery 构建跟踪代码,则基本上返回 false),并执行必要的操作(如果链接被重定向,则将页面重定向到必要的地址单击或触发其他默认操作),但要重新创建所有可能的操作和回调组合,需要进行大量仔细的工作。

      另一种方法是: 1) 在事件数据中查找特定于您的代码的内容 2)如果它不存在 - 进行 AJAX 调用并在其回调中重新触发相同的元素,但这次将您的特定位添加到偶数数据中; AJAX 调用后返回 false 3) 如果数据中存在您的特定位 - 只需什么都不做,允许进行默认事件处理。

      然而,这两种方法都可能会受到影响。

      【讨论】:

        【解决方案5】:

        因此,如果我理解正确,您希望在页面卸载并遵循链接 href 之前完成 ajax 日志。这听起来像是一个完美的案例,您可以考虑在 jQuery 中使用 Deferreds

        当您的用户点击任何应该让他离开页面的内容时,只需检查您的promise 状态即可。如果没有解决,您可以在页面上抛出一个模式窗口,并要求用户等待直到进度完成。然后,将新的pipe 添加到您的deferred,告诉它在一切完成后更改location href

        如果是这种情况,请告诉我。如果是,我会更详细地解释。如果我没有正确理解您的要求,则继续无用

        【讨论】:

        • 脚本需要对用户透明地工作,所以我不能使用模态窗口。
        • @maxt3r - 如果你想转到另一个页面,并且当前页面上还有待处理的项目,让用户知道不是更好吗?
        • 不,此脚本用于分析,客户不应该知道这一点。它也不应该过多地影响页面性能。
        猜你喜欢
        • 1970-01-01
        • 2012-08-25
        • 1970-01-01
        • 1970-01-01
        • 2013-03-28
        • 1970-01-01
        • 2017-11-17
        • 2013-02-02
        • 1970-01-01
        相关资源
        最近更新 更多