用简单的JavaScript的代码捕获XMLHttpRequest

1,812 阅读2分钟

译者:道奇
作者:Dmitri Pavlutin
原文:Catch the XMLHttpRequest in Plain JavaScript

当编写Chrome扩展时,有时我需要捕获JavaScript应用程序启动和结束XMLHttpRequest (XHR)时的事件,但是因为注入到web页面上下文的脚本不会修改原始的应用程序,这件事就很难做到,因为纯XHR本身也不会触发全局事件。

有一些库,如jQuery,确实触发了全局事件ajaxStartajaxStop,甚至提供了全局ajax事件API。不幸的是,只有在使用库方法进行AJAX调用时才会触发这些事件。由于封装的原因,应用程序可以抑制这些事件,设置全局选项为false:

 $.ajax({
  url: "test.html",
  global: false
});

调查

JavaScript提供了对任何对象原型进行修改的方法,包括像XMLHttpRequest这样的host对象,我们可以通过这些方法插入自定义行为。open()send()将被包含自定义逻辑的新方法覆盖,然后再调用原来的方法。

让我们先确保XMLHttpRequest.prototype.openXMLHttpRequest.prototype.send是可写的(writable):

var openDescriptor = Object.getOwnPropertyDescriptor(XMLHttpRequest.prototype, 'open'),
 sendDescriptor = Object.getOwnPropertyDescriptor(XMLHttpRequest.prototype, 'send');

openDescriptor // prints {"writable": true, "configurable": true, ...}
sendDescriptor // prints {"writable": true, "configurable": true, ...}

Object.getOwnPropertyDescriptor()方法可以得到对象属性的设置(描述),要重写XMLHttpRequest对象的方法,需要将属性的writable设置为true:这样我们就可以修改属性了。

捕获请求

使用以下代码段来确定XMLHttpRequest何时开始和结束:

var open = window.XMLHttpRequest.prototype.open,
  send = window.XMLHttpRequest.prototype.send;

function openReplacement(method, url, async, user, password) {
  this._url = url;
  return open.apply(this, arguments);
}

function sendReplacement(data) {
  if(this.onreadystatechange) {
    this._onreadystatechange = this.onreadystatechange;
  }
  /**
   * 当请求发出后,将你的代码放在这里  
   */
  this.onreadystatechange = onReadyStateChangeReplacement;
  return send.apply(this, arguments);
}

function onReadyStateChangeReplacement() {
  /**
   * 将readystatechange的代码放在这里
   */
  if(this._onreadystatechange) {
    return this._onreadystatechange.apply(this, arguments);
  }
}

window.XMLHttpRequest.prototype.open = openReplacement;
window.XMLHttpRequest.prototype.send = sendReplacement;

先把原始open()send()的引用保存下来,然后定义XMLHttpRequest的新方法:openReplacement()sendReplacement(),它们执行自定义代码,再使用Function.apply()调用原始方法,最后,将新方法分配给XMLHttpRequest.prototype。因为修改了类原型,所以XMLHttpRequest的任何新实例都将使用自定义方法。 请注意,覆盖的代码段的应用应该在任何XHR请求启动之前。

例子

查看代码示例,演示了如何捕获发送和完成事件。

另请参阅 XMLHttpRequest