Страницы

Поиск по вопросам

четверг, 26 декабря 2019 г.

Как перехватить ответ сервера в XMLHttpRequest?

#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

Комментариев нет:

Отправить комментарий