Перехват XMLHttpRequest и изменение responseText

Я пытаюсь создать script, который будет выступать в качестве прокси-оболочки для собственного объекта XMLHttpRequest, позволяя мне перехватить его, изменить ответный текст и вернуться к исходному событию onreadystatechange.

Контекст, если данные, которые приложение пытается получить, уже доступно в локальном хранилище, чтобы прервать XMLHttpRequest и передать локально сохраненные данные обратно в методы обратного вызова успеха/отказа приложений. Предположим, что у меня нет контроля над существующими методами обратного вызова AJAX.

Я изначально попробовал следующую идею.

var send = XMLHttpRequest.prototype.send;
XMLHttpRequest.prototype.send = function(data){
   //Do some stuff in here to modify the responseText
   send.call(this, data);
};

Но, как я уже установил, responseText читается только.

Затем я попытался сделать шаг назад, написав собственный собственный собственный прокси-сервер до XMLHttpRequest, в конечном итоге закончив тем, что написал собственную версию собственных методов. Подобно тому, что обсуждается здесь...

http://www.ilinsky.com/articles/XMLHttpRequest/#implementation-wrapping

Но он быстро запутался и все еще испытывает трудности с возвратом измененных данных обратно в оригинальный метод onReadyStateChange.

Любые предложения? Возможно ли это?

Ответ 1

//
// firefox, ie8+ 
//
var accessor = Object.getOwnPropertyDescriptor(XMLHttpRequest.prototype, 'responseText');

Object.defineProperty(XMLHttpRequest.prototype, 'responseText', {
	get: function() {
		console.log('get responseText');
		return accessor.get.call(this);
	},
	set: function(str) {
		console.log('set responseText: %s', str);
		//return accessor.set.call(this, str);
	},
	configurable: true
});


//
// chrome, safari (accessor == null)
//
var rawOpen = XMLHttpRequest.prototype.open;

XMLHttpRequest.prototype.open = function() {
	if (!this._hooked) {
		this._hooked = true;
		setupHook(this);
	}
	rawOpen.apply(this, arguments);
}

function setupHook(xhr) {
	function getter() {
		console.log('get responseText');

		delete xhr.responseText;
		var ret = xhr.responseText;
		setup();
		return ret;
	}

	function setter(str) {
		console.log('set responseText: %s', str);
	}

	function setup() {
		Object.defineProperty(xhr, 'responseText', {
			get: getter,
			set: setter,
			configurable: true
		});
	}
	setup();
}

Ответ 2

Ваш шаг назад - это излишество: вы можете добавить свой собственный getter на XMLHttpRequest: (подробнее о свойствах)

Object.defineProperty(XMLHttpRequest.prototype,"myResponse",{
  get: function() {
    return this.responseText+"my update"; // anything you want
  }
});

использование:

var xhr = new XMLHttpRequest();
...
console.log(xhr.myResponse); // xhr.responseText+"my update"

Примечание в современных браузерах вы можете запустить xhr.onload (см. Рекомендации XMLHttpRequest2)

Ответ 3

Следующие script отлично перехватывают данные перед отправкой через XMLHttpRequest.prototype.send

<script>
(function(send) { 

        XMLHttpRequest.prototype.send = function(data) { 

            this.addEventListener('readystatechange', function() { 

            }, false); 

            console.log(data); 
            alert(data); 

        }; 

})(XMLHttpRequest.prototype.send);
</script>