#javascript #xmlhttprequest
Можно ли имея возможность изменить (inject) XMLHttpRequest изменить его так, чтобы можно было перехватить содержимое ответа не подменяя целиком весь объект со всеми его методами ? Предполагается, что далее в коде будут вызовы вроде: x = new XMLHttpRequest(); x.open( "GET", "/" ); x.onreadystatechange = function () {...}; x.send( null ); или даже с учетом однопоточности: x = new XMLHttpRequest(); x.open( "GET", "/" ); x.send( null ); x.onreadystatechange = function () {...};
Ответы
Ответ 1
Решение для Blink Blink - это Chrome, Opera etc. В прототипе XMLHttpRequest onreadystatechange объявлен как геттер/сеттер и задавая свой геттер/сеттер нужно не сломать логику работы XMLHttpRequest: var oldXMLHttpRequest = XMLHttpRequest; XMLHttpRequest = function() { var xhr = new oldXMLHttpRequest(); // получаем дескриптор прототипных setter/getter var descrGetSet = Object.getOwnPropertyDescriptor( Object.getPrototypeOf( xhr ), "onreadystatechange" ); var newSet = function( val ) { console.log ( "setter" ); descrGetSet.set.call( xhr, function() { // прототипный setter console.log( "Inject "+this.status ); // this.responseText return val.apply( xhr, arguments ); } ); } Object.defineProperty( xhr, "onreadystatechange", { set: newSet, // новый setter get: descrGetSet.get // старый getter } ); return xhr; } Теперь сделав: x = new XMLHttpRequest(); x.open( "GET", "/" ); x.send( null ) x.onreadystatechange = function () { console.log( this.statusText+' is 2' )}; Увидим Inject 200 OK is 2 Inject 200 OK is 2 Inject 200 OK is 2 Что и должно быть при смене readyState. Решение для Webkit Webkit - Safari, PhantomJS Проблема в этом движке- onreadystatechange это геттер/сеттер объекта XHR, а не XHR.prototype. В итоге переопределить его нельзя. Унаследоваться от XHR тоже нельзя, поэтому нужно применять обертку для XHR. Весьма хороша эта обертка: https://github.com/ilinsky/xmlhttprequest
Комментариев нет:
Отправить комментарий