JavaScript检测到AJAX事件


78

好的,基本上,我想在页面上放置一些javascript,以某种方式附加某种全局事件侦听器,该侦听器可以在发出ajax请求时检测并执行某些操作(无需直接从调用中调用它),而不管ajax如何打电话了。

我想出了如何使用jquery-如果ajax请求是jquery完成。这是一个示例代码:

$.post(
  // requested script
  'someScript.php', 
  // data to send
  {
    'foo' : 'bar',
    'a' : 'b'
  },
  // receive response
  function(response){
    // do something
  }
); // .post

// global event listener    
$(document).ajaxSend(
  function(event,request,settings){
    alert(settings.url); // output: "someScript.php"
    alert(settings.data); // output: "foo=bar&a=b"
  }
);

使用此代码,无论我在哪里/如何调用$ .post(..),全局事件监听器都会触发。如果我使用$ .get或$ .ajax(任何jquery ajax方法),无论我如何调用它/何时调用(附加为onclick,页面加载等),它也都可以使用。

但是,我希望能够扩展此侦听器以触发,无论使用什么js框架,甚至不使用任何框架。因此,例如,如果我在页面上包含以下代码(w3schools的通用ajax代码):

function loadXMLDoc()
{
if (window.XMLHttpRequest)
  {// code for IE7+, Firefox, Chrome, Opera, Safari
  xmlhttp=new XMLHttpRequest();
  }
else
  {// code for IE6, IE5
  xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
  }
xmlhttp.onreadystatechange=function()
  {
  if (xmlhttp.readyState==4 && xmlhttp.status==200)
    {
    document.getElementById("myDiv").innerHTML=xmlhttp.responseText;
    }
  }
xmlhttp.open("GET","test.txt",true);
xmlhttp.send();
}

然后,我有一些随机链接到该函数一个onclick调用,我的全局AJAX事件侦听器应该能够同时检测到这一请求。好吧,我将该代码添加到了页面中,并将其附加到了随机链接的onclick上(是的,代码本身可以工作),但是上面的“全局事件监听器” jQuery代码未能检测到该调用。

我做了更多的挖掘工作,我知道我基本上可以将对象保存到temp对象,并用“包装器”对象覆盖当前对象,该“包装器”对象将调用指定的函数,然后调用temp函数,但这需要我提前知道创建/使用原始对象的时间。但是我永远不会总是提前知道...

那么...这可能吗?是否有某种方法可以检测到发出的ajax获取/发布请求,而不管它是使用通用对象还是通过xyz框架完成的?还是我只需要制作重复的代码来处理每个框架,并且还提前知道正在创建/使用的ajax对象?

编辑:

我忘了提一下,仅检测到一个请求是不够的。我还需要捕获请求中发送的数据。以下评论中提供的链接将帮助您确定是否发出了“ a”请求,但未获取发送的数据。ps-至少在我看来,以下链接中提供的答案不是很清楚。



感谢您的链接!这个问题不完全是那个问题,因为我还需要能够捕获请求中发送的数据(我想我忽略了这个问题;编辑了它)。但是,它直接使我步入正轨,我认为我找到了一个解决方案,它将在测试完成后发布。谢谢!
蜡笔暴力

我认为您正在寻找的是有关操纵原型的问题,但以一种更好的方式进行了stackoverflow.com/q/20689481/3462483
doz87

Answers:


108

好的,这是我到目前为止提出的:

<script type='text/javascript'>
var s_ajaxListener = new Object();
s_ajaxListener.tempOpen = XMLHttpRequest.prototype.open;
s_ajaxListener.tempSend = XMLHttpRequest.prototype.send;
s_ajaxListener.callback = function () {
  // this.method :the ajax method used
  // this.url    :the url of the requested script (including query string, if any) (urlencoded) 
  // this.data   :the data sent, if any ex: foo=bar&a=b (urlencoded)
}

XMLHttpRequest.prototype.open = function(a,b) {
  if (!a) var a='';
  if (!b) var b='';
  s_ajaxListener.tempOpen.apply(this, arguments);
  s_ajaxListener.method = a;  
  s_ajaxListener.url = b;
  if (a.toLowerCase() == 'get') {
    s_ajaxListener.data = b.split('?');
    s_ajaxListener.data = s_ajaxListener.data[1];
  }
}

XMLHttpRequest.prototype.send = function(a,b) {
  if (!a) var a='';
  if (!b) var b='';
  s_ajaxListener.tempSend.apply(this, arguments);
  if(s_ajaxListener.method.toLowerCase() == 'post')s_ajaxListener.data = a;
  s_ajaxListener.callback();
}
</script>

方向:

只需将其c / p到您的页面上,或将其包含在.js文件中或任何其他内容中即可。这将创建一个名为s_ajaxListener的对象。每当发出AJAX GET或POST请求时,都会调用s_ajaxListener.callback(),并且以下属性可用:

s_ajaxListener.method:使用的ajax方法。这应该是GET或POST。注意:该值可能并不总是大写,这取决于特定请求的编码方式。我正在讨论自动将其大写或将其留给toLowerCase()进行区分大小写的比较的智慧。

s_ajaxListener.url:所请求脚本的URL(包括查询字符串,如果有的话)(使用urlencoded)。我注意到,取决于数据的发送方式以及从哪个浏览器/框架发送数据,例如,该值最终可能是“”或“ +”或“%20”。我正在讨论在此处解码或将其留给其他东西的智慧。

s_ajaxListener.data:发送的数据,如果有的话,例如:foo = bar&a = b(与.url相同的“问题”,并使用url编码)

笔记:

就目前而言,这与IE6不兼容。这个解决方案对我来说还不够好,因为我希望它与IE6兼容。但是由于很多其他人都不关心IE6,所以我决定将解决方案发布到当前状态,因为如果您不关心IE6,它应该对您有用。

我已经在(截至发布日期)对此进行了测试:当前的Safari,当前的Chrome,当前的FireFox,IE8,IE8(与IE7兼容)。它当前不适用于IE6,因为IE6使用ActiveX对象,而实际上其他所有东西都使用XMLHttpRequest。

现在,我没有任何线索,基本上,原型/扩展/重载(?)ActiveXObject(“ Microsoft.XMLHTTP”)。这就是我目前正在研究的...有人知道吗?

在我上面测试过的每种浏览器下,它都可以处理来自通用对象以及jquery和原型框架的AJAX请求。我知道还有其他框架,但是IMO这两个是主要的框架。我可能会对MooTools进行质量检查,但除此之外,我只测试它们就可以了。

如果有人想通过测试和发布有关其他浏览器和/或框架的结果做出贡献,将不胜感激:)


1
您可以像sarissa一样为IE6定义包装函数。看一下Re-inventing XMLHttpRequest以了解如何做到这一点(我现在没有时间)。您不能扩展ActiveX对象,但是可以扩展自己的包装器函数,该包装器函数仅模拟所需的属性。我认为大多数库都会测试是否存在window.XMLHttpRequest和包装对象。
马塞尔·科佩尔

另请注意,IE7兼容模式下的IE8≠IE7。我怀疑XMLHttpRequest对象是不同的事物之一:在IE7中,它似乎只是ActiveX组件上的包装函数,而在IE8中,它可能被实现为“真实的” XHR对象。
Marcel Korpel 2010年

1
目前在FireFox中不起作用。XMLHttpRequest.open.apply错误了
HMR

仍然可以正常运行,但是由于某种原因XMLHttpRequest.send,Chrome中的每次点击都会被调用,并且回调最终会在每次点击时执行
Petr Gazarov

@PetrGazarov有趣..我想知道这是否是预取的副作用?
蜡笔暴力

5

为了实现IE 6兼容性,如何:

<script type='text/javascript'>
  var s_ajaxListener = new Object();

  // Added for IE support
  if (typeof XMLHttpRequest === "undefined") {
    XMLHttpRequest = function () {
      try { return new ActiveXObject("Msxml2.XMLHTTP.6.0"); }
      catch (e) {}
      try { return new ActiveXObject("Msxml2.XMLHTTP.3.0"); }
      catch (e) {}
      try { return new ActiveXObject("Microsoft.XMLHTTP"); }
      catch (e) {}
      throw new Error("This browser does not support XMLHttpRequest.");
    };
  }

  s_ajaxListener.tempOpen = XMLHttpRequest.prototype.open;
  s_ajaxListener.tempSend = XMLHttpRequest.prototype.send;
  s_ajaxListener.callback = function () {
    // this.method :the ajax method used
    // this.url    :the url of the requested script (including query string, if any) (urlencoded) 
    // this.data   :the data sent, if any ex: foo=bar&a=b (urlencoded)
  }

  XMLHttpRequest.prototype.open = function(a,b) {
    if (!a) var a='';
    if (!b) var b='';
    s_ajaxListener.tempOpen.apply(this, arguments);
    s_ajaxListener.method = a;  
    s_ajaxListener.url = b;
    if (a.toLowerCase() == 'get') {
      s_ajaxListener.data = b.split('?');
      s_ajaxListener.data = s_ajaxListener.data[1];
    }
  }

  XMLHttpRequest.prototype.send = function(a,b) {
    if (!a) var a='';
    if (!b) var b='';
    s_ajaxListener.tempSend.apply(this, arguments);
    if(s_ajaxListener.method.toLowerCase() == 'post')s_ajaxListener.data = a;
    s_ajaxListener.callback();
  }
</script>

6
是的,那几乎是我当时的工作。.但是IE6不再受任何支持,尤其是自2014
Crayon Violent
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.