2013-06-06 15 views
11

Sto cercando di creare uno script che funga da proxy/wrapper per l'oggetto nativo XMLHttpRequest che mi consente di intercettarlo, modificare il responseText e tornare all'evento originale onreadystatechange.Intercept XMLHttpRequest e modifica responseText

Il contesto di essere, se i dati l'applicazione sta cercando di ricevere è già disponibile in memoria locale, per interrompere il XMLHttpRequest e passare i dati memorizzati localmente nuovamente dentro i metodi di callback apps successo/insuccesso. Supponiamo che non abbia alcun controllo sulle app esistenti metodi di callback AJAX.

avevo inizialmente provato la seguente idea ..

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

Ma, come ho ormai consolidata, il responseText è di sola lettura.

Allora ho provato facendo un passo indietro, scrivere il mio delega nativa per XMLHttpRequest, in ultima analisi, di finire a scrivere la mia versione dei metodi nativi. Simile a quello che viene discusso qui ...

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

Ma rapidamente ottenuto confuso, e avere ancora la difficoltà di restituire i dati modificati di nuovo nel metodo originale onReadyStateChange.

Qualche suggerimento? È possibile?

risposta

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

Questo era eccessivo per quello di cui avevo bisogno, ma la chiave che mi portava era "var rawOpen = XMLHttpRequest.prototype.open;" e "rawOpen.apply (this, arguments);", che mi permetteva di collegare il mio override (come si mostra), ma lascia comunque passare la chiamata normalmente, in modo che il chiamante non sappia nulla di diverso. –

0

tuo step-back è un eccessivo: si può aggiungere la tua getter su XMLHttpRequest: (more about properties)

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

l'utilizzo:

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

Nota sul browser moderni si può correre xhr.onload (vedi XMLHttpRequest2 tips)

+0

Grazie. Ho provato a utilizzare questa idea, ma ho bisogno di xhr.responseText per essere modificato. Aggiungendo il nuovo valore, "myResponse", significherebbe dover cambiare il codice dell'app nell'evento onReadyStateChange per utilizzare .myResponse piuttosto che .responseText. – james

0

Il seguente script intercetta perfettamente i dati prima di inviare via 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>