Vorrei acquisire il contenuto delle richieste AJAX utilizzando Greasemonkey.Come posso intercettare XMLHttpRequests da uno script Greasemonkey?
Qualcuno sa come fare?
Vorrei acquisire il contenuto delle richieste AJAX utilizzando Greasemonkey.Come posso intercettare XMLHttpRequests da uno script Greasemonkey?
Qualcuno sa come fare?
Non so se lo si può fare con greasemonkey, ma se si crea un'estensione, è possibile utilizzare il servizio di osservazione e l'osservatore di risposta http-on-examination-response.
Come modificare il XMLHttpRequest.prototype.open o inviare metodi con sostituzioni che impostano i propri callback e chiamano i metodi originali? Il callback può fare la sua cosa e quindi chiamare il callback il codice originale specificato.
In altre parole:
XMLHttpRequest.prototype.realOpen = XMLHttpRequest.prototype.open;
var myOpen = function(method, url, async, user, password) {
//do whatever mucking around you want here, e.g.
//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 ;
è possibile sostituire l'oggetto unsafeWindow.XMLHttpRequest nel documento con un involucro. Un po 'di codice (non testato):
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
};
};
Ma questo ha un piccolo problema: script di Greasemonkey eseguono dopo caricamento di una pagina, in modo che la pagina possa utilizzare o conservare l'oggetto XMLHttpRequest originale durante la sua sequenza di caricamento, lo richieda fatto prima dell'esecuzione dello script, o con il vero oggetto XMLHttpRequest non sarebbe tracciato dal tuo script. In nessun modo posso vedere per aggirare questa limitazione.
Ho scritto un codice per intercettare le chiamate ajax, durante la scrittura del server proxy. Dovrebbe funzionare sulla maggior parte dei browser.
La risposta accettata è quasi corretta, ma potrebbe utilizzare un leggero miglioramento:
(function(open) {
XMLHttpRequest.prototype.open = function() {
this.addEventListener("readystatechange", function() {
console.log(this.readyState);
}, false);
open.apply(this, arguments);
};
})(XMLHttpRequest.prototype.open);
preferiscono utilizzare applicare + argomenti su chiamata perché allora non c'è bisogno per conoscere esplicitamente tutti gli argomenti che vengono dati ad aprire che potrebbero cambiare!
Testato in Chrome 55 e Firefox 50.1.0
Nel mio caso ho voluto modificare il responseText, che in Firefox era una proprietà di sola lettura, quindi ho dovuto avvolgere l'intero oggetto XMLHttpRequest. Non ho implementato l'intera API (in particolare il responseType), ma è stato abbastanza buono da usare per tutte le librerie che ho.
Usage:
XHRProxy.addInterceptor(function(method, url, responseText, status) {
if (url.endsWith('.html') || url.endsWith('.htm')) {
return "<!-- HTML! -->" + responseText;
}
});
Codice:
(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);