Skip to content

Instantly share code, notes, and snippets.

@benjamingr
Created January 15, 2019 20:18
Show Gist options
  • Star 42 You must be signed in to star a gist
  • Fork 17 You must be signed in to fork a gist
  • Save benjamingr/0433b52559ad61f6746be786525e97e8 to your computer and use it in GitHub Desktop.
Save benjamingr/0433b52559ad61f6746be786525e97e8 to your computer and use it in GitHub Desktop.
function interceptNetworkRequests(ee) {
const open = XMLHttpRequest.prototype.open;
const send = XMLHttpRequest.prototype.send;
const isRegularXHR = open.toString().indexOf('native code') !== -1;
// don't hijack if already hijacked - this will mess up with frameworks like Angular with zones
// we work if we load first there which we can.
if (isRegularXHR) {
XMLHttpRequest.prototype.open = function() {
ee.onOpen && ee.onOpen(this, arguments);
if (ee.onLoad) {
this.addEventListener('load', ee.onLoad.bind(ee));
}
if (ee.onError) {
this.addEventListener('error', ee.onError.bind(ee));
}
return open.apply(this, arguments);
};
XMLHttpRequest.prototype.send = function() {
ee.onSend && ee.onSend(this, arguments);
return send.apply(this, arguments);
};
}
const fetch = window.fetch || "";
// don't hijack twice, if fetch is built with XHR no need to decorate, if already hijacked
// then this is dangerous and we opt out
const isFetchNative = fetch.toString().indexOf('native code') !== -1;
if(isFetchNative) {
window.fetch = function () {
ee.onFetch && ee.onFetch(arguments);
const p = fetch.apply(this, arguments);
p.then(ee.onFetchResponse, ee.onFetchError);
return p;
};
// at the moment, we don't listen to streams which are likely video
const json = Response.prototype.json;
const text = Response.prototype.text;
const blob = Response.prototype.blob;
Response.prototype.json = function () {
const p = json.apply(this.arguments);
p.then(ee.onFetchLoad && ee.onFetchLoad.bind(ee, "json"));
return p;
};
Response.prototype.text = function () {
const p = text.apply(this.arguments);
p.then(ee.onFetchLoad && ee.onFetchLoad.bind(ee, "text"));
return p;
};
Response.prototype.blob = function () {
const p = blob.apply(this.arguments);
p.then(ee.onFetchLoad && ee.onFetchLoad.bind(ee, "blob"));
return p;
};
}
return ee;
}
interceptNetworkRequests({
onFetch: console.log,
onFetchResponse: console.log,
onFetchLoad: console.log,
onOpen: console.log,
onSend: console.log,
onError: console.log,
onLoad: console.log
});
@acerbastimur
Copy link

Thanks

@benjamingr
Copy link
Author

@acerbastimur sure, there are libraries that do this better - this is just a useful trick I use to debug things.

I think netflix has a library for this https://github.com/Netflix/pollyjs

@pbreah
Copy link

pbreah commented Mar 7, 2021

On line 53 (inside the blob prototype) would be good to also get the response headers for blobs. On my use case (not patching on fetch the initial page load) I don't get the onFetchResponse called (I think a lib is caching a copy of fetch somewhere - so this is not doing anything). I do get the Response.prototype.blob function called, but I also need the header to see if this is a network call I want or not.

@JKamsker
Copy link

fetching text doesnt seem to work
image
await (await window.fetchOriginal("https://pastebin.com/raw/SMOETHING")).text();

This call would work without the hook....

@luwes
Copy link

luwes commented Nov 30, 2021

this.arguments should be this, arguments

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment