我如何拦截Greasemonkey脚本中的XMLHttpRequests?

我想使用Greasemonkey捕获AJAX请求的内容。

有谁知道如何做到这一点?

接受的答案几乎是正确的,但可以稍微改进:

(function(open) { XMLHttpRequest.prototype.open = function() { this.addEventListener("readystatechange", function() { console.log(this.readyState); }, false); open.apply(this, arguments); }; })(XMLHttpRequest.prototype.open); 

更喜欢使用apply +参数来调用,因为那样你就不必显式地知道所有打开的参数了。

如何修改XMLHttpRequest.prototype.open或发送方法与置换自己的callback和调用原始方法? callback可以做它的事情,然后调用指定的原始代码的callback。

换一种说法:

 XMLHttpRequest.prototype.realOpen = XMLHttpRequest.prototype.open; var myOpen = function(method, url, async, user, password) { //do whatever mucking around you want here, eg //changing the onload callback to your own version //call original this.realOpen (method, url, async, user, password); } //ensure all XMLHttpRequests use our custom open method XMLHttpRequest.prototype.open = myOpen ; 

您可以使用包装器replace文档中的unsafeWindow.XMLHttpRequest对象。 一个小代码(未testing):

 var oldFunction = unsafeWindow.XMLHttpRequest; unsafeWindow.XMLHttpRequest = function() { alert("Hijacked! XHR was constructed."); var xhr = oldFunction(); return { open: function(method, url, async, user, password) { alert("Hijacked! xhr.open()."); return xhr.open(method, url, async, user, password); } // TODO: include other xhr methods and properties }; }; 

但这有一个小问题: 加载页面执行Greasemonkey脚本,因此页面可以在加载序列期间使用或存储原始的XMLHttpRequest对象,因此在执行脚本之前执行的请求或者使用真实的XMLHttpRequest对象进行的跟踪将不会被跟踪通过你的脚本。 没有办法,我可以看到解决这个限制。

我在编写代理服务器时编写了一些拦截Ajax调用的代码。 它应该在大多数浏览器上工作。

这里是: https : //github.com/creotiv/AJAX-calls-intercepter

不知道你是否可以用greasemonkey做到这一点,但是如果你创build了一个扩展,那么你可以使用观察者服务和http-on-examine-response观察者。

在Chrome 55和Firefox 50.1.0中testing

在我的情况下,我想修改responseText,在Firefox是一个只读属性,所以我不得不包装整个XMLHttpRequest对象。 我还没有实现整个API(特别是responseType),但是对于我所有的库来说,这已经足够了。

用法:

  XHRProxy.addInterceptor(function(method, url, responseText, status) { if (url.endsWith('.html') || url.endsWith('.htm')) { return "<!-- HTML! -->" + responseText; } }); 

码:

 (function(window) { var OriginalXHR = XMLHttpRequest; var XHRProxy = function() { this.xhr = new OriginalXHR(); function delegate(prop) { Object.defineProperty(this, prop, { get: function() { return this.xhr[prop]; }, set: function(value) { this.xhr.timeout = value; } }); } delegate.call(this, 'timeout'); delegate.call(this, 'responseType'); delegate.call(this, 'withCredentials'); delegate.call(this, 'onerror'); delegate.call(this, 'onabort'); delegate.call(this, 'onloadstart'); delegate.call(this, 'onloadend'); delegate.call(this, 'onprogress'); }; XHRProxy.prototype.open = function(method, url, async, username, password) { var ctx = this; function applyInterceptors(src) { ctx.responseText = ctx.xhr.responseText; for (var i=0; i < XHRProxy.interceptors.length; i++) { var applied = XHRProxy.interceptors[i](method, url, ctx.responseText, ctx.xhr.status); if (applied !== undefined) { ctx.responseText = applied; } } } function setProps() { ctx.readyState = ctx.xhr.readyState; ctx.responseText = ctx.xhr.responseText; ctx.responseURL = ctx.xhr.responseURL; ctx.responseXML = ctx.xhr.responseXML; ctx.status = ctx.xhr.status; ctx.statusText = ctx.xhr.statusText; } this.xhr.open(method, url, async, username, password); this.xhr.onload = function(evt) { if (ctx.onload) { setProps(); if (ctx.xhr.readyState === 4) { applyInterceptors(); } return ctx.onload(evt); } }; this.xhr.onreadystatechange = function (evt) { if (ctx.onreadystatechange) { setProps(); if (ctx.xhr.readyState === 4) { applyInterceptors(); } return ctx.onreadystatechange(evt); } }; }; XHRProxy.prototype.addEventListener = function(event, fn) { return this.xhr.addEventListener(event, fn); }; XHRProxy.prototype.send = function(data) { return this.xhr.send(data); }; XHRProxy.prototype.abort = function() { return this.xhr.abort(); }; XHRProxy.prototype.getAllResponseHeaders = function() { return this.xhr.getAllResponseHeaders(); }; XHRProxy.prototype.getResponseHeader = function(header) { return this.xhr.getResponseHeader(header); }; XHRProxy.prototype.setRequestHeader = function(header, value) { return this.xhr.setRequestHeader(header, value); }; XHRProxy.prototype.overrideMimeType = function(mimetype) { return this.xhr.overrideMimeType(mimetype); }; XHRProxy.interceptors = []; XHRProxy.addInterceptor = function(fn) { this.interceptors.push(fn); }; window.XMLHttpRequest = XHRProxy; })(window);