2009-03-10 13 views

Respuesta

0

No estoy seguro si puede hacerlo con greasemonkey, pero si crea una extensión, puede usar el servicio de observador y el observador http-on-examine-response.

3

¿Qué le parece modificar el XMLHttpRequest.prototype.open o enviar métodos con reemplazos que configuran sus propias devoluciones de llamada y llaman a los métodos originales? La devolución de llamada puede hacer lo suyo y luego llamar a la devolución de llamada al código original especificado.

En otras palabras:

XMLHttpRequest.prototype.realOpen = XMLHttpRequest.prototype.open; 

var myOpen = function(method, url, async, user, password) { 
    //do whatever mucking around you want here, e.g. 
    //changing the onload callback to your own version 


    //call original 
    this.realOpen (method, url, async, user, password); 
} 


//ensure all XMLHttpRequests use our custom open method 
XMLHttpRequest.prototype.open = myOpen ; 
1

puede reemplazar el objeto unsafeWindow.XMLHttpRequest en el documento con un envoltorio. Un poco de código (no probado):

var oldFunction = unsafeWindow.XMLHttpRequest; 
unsafeWindow.XMLHttpRequest = function() { 
    alert("Hijacked! XHR was constructed."); 
    var xhr = oldFunction(); 
    return { 
    open: function(method, url, async, user, password) { 
     alert("Hijacked! xhr.open()."); 
     return xhr.open(method, url, async, user, password); 
    } 
    // TODO: include other xhr methods and properties 
    }; 
}; 

Pero esto tiene un pequeño problema: scripts de Greasemonkey ejecutan después se carga una página, por lo que la página se puede usar o almacenar el objeto XMLHttpRequest original durante su secuencia de carga, por lo que las solicitudes hecho antes de que se ejecute el script, o con el objeto real XMLHttpRequest no se seguiría por su script. No hay manera de que pueda verlo para evitar esta limitación.

34

La respuesta aceptada es casi correcta, pero podría utilizar una ligera mejora:

(function(open) { 
    XMLHttpRequest.prototype.open = function() { 
     this.addEventListener("readystatechange", function() { 
      console.log(this.readyState); 
     }, false); 
     open.apply(this, arguments); 
    }; 
})(XMLHttpRequest.prototype.open); 

prefieren usar solicitar + argumentos sobre la llamada porque entonces usted no tiene ¡para saber explícitamente todos los argumentos que se están dando para abrir que podrían cambiar!

0

Probado en Chrome 55 y Firefox 50.1.0

En mi caso quería modificar el responseText, que en Firefox era una propiedad de sólo lectura, así que tuve que envolver la totalidad del objeto XMLHttpRequest. No he implementado la API completa (en particular, el responseType), pero fue lo suficientemente bueno para todas las bibliotecas que tengo.

Uso:

XHRProxy.addInterceptor(function(method, url, responseText, status) { 
     if (url.endsWith('.html') || url.endsWith('.htm')) { 
      return "<!-- HTML! -->" + responseText; 
     } 
    }); 

Código:

(function(window) { 

    var OriginalXHR = XMLHttpRequest; 

    var XHRProxy = function() { 
     this.xhr = new OriginalXHR(); 

     function delegate(prop) { 
      Object.defineProperty(this, prop, { 
       get: function() { 
        return this.xhr[prop]; 
       }, 
       set: function(value) { 
        this.xhr.timeout = value; 
       } 
      }); 
     } 
     delegate.call(this, 'timeout'); 
     delegate.call(this, 'responseType'); 
     delegate.call(this, 'withCredentials'); 
     delegate.call(this, 'onerror'); 
     delegate.call(this, 'onabort'); 
     delegate.call(this, 'onloadstart'); 
     delegate.call(this, 'onloadend'); 
     delegate.call(this, 'onprogress'); 
    }; 
    XHRProxy.prototype.open = function(method, url, async, username, password) { 
     var ctx = this; 

     function applyInterceptors(src) { 
      ctx.responseText = ctx.xhr.responseText; 
      for (var i=0; i < XHRProxy.interceptors.length; i++) { 
       var applied = XHRProxy.interceptors[i](method, url, ctx.responseText, ctx.xhr.status); 
       if (applied !== undefined) { 
        ctx.responseText = applied; 
       } 
      } 
     } 
     function setProps() { 
      ctx.readyState = ctx.xhr.readyState; 
      ctx.responseText = ctx.xhr.responseText; 
      ctx.responseURL = ctx.xhr.responseURL; 
      ctx.responseXML = ctx.xhr.responseXML; 
      ctx.status = ctx.xhr.status; 
      ctx.statusText = ctx.xhr.statusText; 
     } 

     this.xhr.open(method, url, async, username, password); 

     this.xhr.onload = function(evt) { 
      if (ctx.onload) { 
       setProps(); 

       if (ctx.xhr.readyState === 4) { 
        applyInterceptors(); 
       } 
       return ctx.onload(evt); 
      } 
     }; 
     this.xhr.onreadystatechange = function (evt) { 
      if (ctx.onreadystatechange) { 
       setProps(); 

       if (ctx.xhr.readyState === 4) { 
        applyInterceptors(); 
       } 
       return ctx.onreadystatechange(evt); 
      } 
     }; 
    }; 
    XHRProxy.prototype.addEventListener = function(event, fn) { 
     return this.xhr.addEventListener(event, fn); 
    }; 
    XHRProxy.prototype.send = function(data) { 
     return this.xhr.send(data); 
    }; 
    XHRProxy.prototype.abort = function() { 
     return this.xhr.abort(); 
    }; 
    XHRProxy.prototype.getAllResponseHeaders = function() { 
     return this.xhr.getAllResponseHeaders(); 
    }; 
    XHRProxy.prototype.getResponseHeader = function(header) { 
     return this.xhr.getResponseHeader(header); 
    }; 
    XHRProxy.prototype.setRequestHeader = function(header, value) { 
     return this.xhr.setRequestHeader(header, value); 
    }; 
    XHRProxy.prototype.overrideMimeType = function(mimetype) { 
     return this.xhr.overrideMimeType(mimetype); 
    }; 

    XHRProxy.interceptors = []; 
    XHRProxy.addInterceptor = function(fn) { 
     this.interceptors.push(fn); 
    }; 

    window.XMLHttpRequest = XHRProxy; 

})(window); 
Cuestiones relacionadas