2013-06-06 13 views
11

Próbuję utworzyć skrypt, który będzie działać jako proxy/opakowanie dla natywnego obiektu XMLHttpRequest, umożliwiając mi przechwycenie go, zmodyfikowanie obiektu responseText i powrót do pierwotnego zdarzenia onreadystatechange.Przechwytuj XMLHttpRequest i zmodyfikuj tekst odpowiedzi

Kontekst oznacza, że ​​jeśli dane, które aplikacja próbuje uzyskać, są już dostępne w pamięci lokalnej, należy przerwać proces XMLHttpRequest i przekazać lokalnie przechowywane dane z powrotem do metod wywołania zwrotnego sukcesu/niepowodzenia aplikacji. Załóżmy, że nie mam żadnej kontroli nad aplikacjami istniejącymi metodami oddzwaniania AJAX.

miałem pierwotnie próbowali następujący pomysł ..

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

Ale jak mam teraz nawiązane, responseText jest tylko do odczytu.

Potem spróbowałem zrobić krok do tyłu, pisząc własne pełne natywne proxy do XMLHttpRequest, ostatecznie kończąc pisanie własnej wersji natywnych metod. Podobny do tego, co jest omawiane tutaj ...

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

Ale to szybko dostaje mylące, a wciąż mają trudności z powrotem zmienione dane z powrotem do oryginalnego onReadyStateChange metody.

Wszelkie sugestie? Czy to możliwe?

Odpowiedz

5

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

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

 

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

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

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

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

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

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

+0

To była przesada dla tego, czego potrzebowałem, ale kluczowym wyjściem dla mnie było 'var rawOpen = XMLHttpRequest.prototype.open;' i 'rawOpen.apply (this, arguments);', które pozwoliło mi podłączyć moje własne nadpisanie (jak pokazano), ale nadal pozwala na normalne przekazywanie połączenia, aby dzwoniący nie wiedział nic innego. –

0

Twój krok do tyłu jest przesadą: można dodać własny getter na XMLHttpRequest: (more about properties)

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

użycie:

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

Uwaga na nowoczesnych przeglądarek można uruchomić xhr.onload (patrz XMLHttpRequest2 tips)

+0

Dzięki. Próbowałem użyć tego pomysłu, ale potrzebuję zmienić xhr.responseText. Dodanie nowej wartości "myResponse" oznaczałoby konieczność zmiany kodu aplikacji w zdarzeniu onReadyStateChange w celu użycia .myResponse zamiast .responseText. – james

0

Poniższy skrypt doskonale przechwytuje dane Przed wysłaniem poprzez 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>