2010-03-01 12 views
16

Estoy desarrollando una clase auxiliar simple para enviar solicitudes usando XmlHttpRequest (código a continuación). Pero no puedo hacer que funcione. En Google cromo, por ejemplo, consigo el error INVALID_STATE_ERR: DOM Exception 11 y en los otros navegadores consigo a == estado 0.INVALID_STATE_ERR: DOM Exception 11

//@method XRequest: Object constructor. As this implements a singleton, the object can't be created calling the constructor, GetInstance should be called instead 
function XRequest() { 
    this.XHR = XRequest.CreateXHR(); 
} 
XRequest.instance = null; 

//@method static GetInstance: Creates a singleton object of type XRequest. Should be called whenever an object of that type is required. 
//@return: an instance of a XRequest object 
XRequest.GetInstance = function() { 
    if(XRequest.instance == null) { 
     XRequest.instance = new XRequest(); 
    } 
    return XRequest.instance; 
} 

//@method static CreateXHR: Implments a basic factory method for creating a XMLHttpRequest object 
//@return: XMLHttp object or null 
XRequest.CreateXHR = function() { 
    var xhr = null; 
    var factory = [ 
     function() { return new XMLHttpRequest(); }, 
     function() { return new ActiveXObject("Msxml2.XMLHTTP"); }, 
     function() { return new ActiveXObject("Microsoft.XMLHTTP"); } 
    ]; 

    for(var i = 0; i < factory.length; ++i) { 
     var f = factory[i]; 
     xhr = f(); 
     if(xhr) return xhr; 
    } 
    return null; 
} 

XRequest.prototype.SetRequestHeader = function(name, value) { 
    if(this.XHR) { 
     this.XHR.setRequestHeader(name, value); 
    } 
} 

XRequest.prototype.SendRequest = function(args) { 
    var async = true; 
    var type = ""; 
    var url = ""; 
    var username = ""; 
    var password = ""; 
    var body = null; 
    var success = null; 
    var failure = null; 

    for(e in args) { 
     switch(e) { 
      case "async": 
       async = args[e]; 
       break; 
      case "type": 
       type = args[e]; 
       break; 
      case "success": 
       success = args[e]; 
       break; 
      case "failure": 
       failure = args[e]; 
       break; 
      case "url": 
       url = args[e]; 
       break; 
      case "username": 
       username = args[e]; 
       break; 
      case "password": 
       password = args[e]; 
       break; 
      case "body": 
       body = args[e]; 
      break; 
      case "setHeader": 
       var h = args[e].split(":"); 
       if(h.length == 2) { 
        this.SetRequestHeader(h[0], h[1]); 
       } 
       break; 
     } 
    } 

    var that = this; 
    this.XHR.onreadystatechange = function() { 
     alert("readyState == " + that.XHR.readyState + " status == " + that.XHR.status); 
     if(that.XHR.readyState == 4) { 
      if(that.XHR.status == 200 || that.XHR.status == 0) { 
       if(success) success(that.XHR); 
      } else { 
       if(failure) failure(); 
      } 
     } 
    }; 
    this.XHR.open(type, url, async, username, password); 
    this.XHR.send(body); 
} 

Ejemplo de uso:

<script language="javascript"> 
    function onLoad() { 
     var x = XRequest.GetInstance(); 
     x.SendRequest({type:"GET", 
      setHeader:"Accept:text/html, image/png, image/*, */*", 
      url: "http://your_server.com/getData?param1=test", 
      success:onSuccess, failure:onFail 
     }); 
    } 

    function onSuccess(obj) { 
     alert("OK");     
    } 

    function onFail() { 
     alert("Not at this time!"); 
    } 
</script> 
+0

No puedo imaginar por qué te molestarías en escribir algo como esto, excepto tal vez por diversión. Esto no responde a su pregunta, pero le aconsejo que haga que ese bucle "for" sea: "for (var e in args) ..." – Pointy

+0

No es por diversión. Esto se ejecutará en un navegador incrustado y el código usa mucho las solicitudes http, por eso lo incluyo dentro de una clase para simplificar su uso. Además, el código aún no está completo. – Andres

+2

Bueno, ¿por qué no usarías simplemente uno de los muchos, muchos frameworks de código abierto que ya proporcionan esa funcionalidad? Ya han resuelto los errores y resuelto los problemas del navegador. – Pointy

Respuesta

9

Independientemente, puede simplificar el método de SendRequest mediante la creación de un mixin en lugar de utilizar un gigante switch.

XRequest.prototype.SendRequest = function(params) { 
    var defaultParams = { 
     async: true, 
     type:  "", 
     url:  "", 
     username: "", 
     password: "", 
     body:  null, 
     success: null, 
     failure: null 
    }; 

    for (var i in defaultParams) { 
     if (defaultParams.hasOwnProperty(i) && typeof params[i] == "undefined") { 
      params[i] = defaultParams[i]; 
     } 
    } 

    var that = this; 
    this.XHR.onreadystatechange = function() { 
     if (that.XHR.readyState == 4) { 
      if (that.XHR.status == 200 || that.XHR.status == 0) { 
       if (params.success) { 
        params.success(that.XHR); 
       } 
      } else { 
       if (params.failure) { 
        params.failure(); 
       } 
      } 
     } 
    }; 

    this.XHR.open(
     params.type, parms.url, params.async, params.username, params.password 
    ); 

    // It doesn't make sense to have a for/switch here when you're only handling 
    // one case 
    if (params.setHeader) { 
     var h = params.setHeader.split(":"); 
     if (h.length == 2) { 
      this.SetRequestHeader(h[0], h[1]); 
     } 
    } 

    this.XHR.send(params.body); 
}; 

También tenga cuidado: sus for..in bucles existentes tienen dos problemas distintos:

  1. no se está usando var y causando un mundial por crear: for (e in args) debería ser for (var e in args)
  2. Siempre que utilice for..in, siempre debe comprobar para asegurarse de que cada clave sea un miembro directo del objeto, y no algo heredado inadvertidamente a través del prototipo

.

for (var i in obj) { 
    if (obj.hasOwnProperty(i)) { 
     // do stuff here 
    } 
} 
40

problema en esta biblioteca ajax .

XHR.setRequestHeader() debe llamarse después de XHR.open().

// @method XRequest: Object constructor. As this implements a singleton, the object can't be created calling the constructor, GetInstance should be called instead 
function XRequest() 
{ 
    this.XHR = XRequest.CreateXHR(); 
} 

XRequest.instance = null; 


// @method static GetInstance: Creates a singleton object of type XRequest. Should be called whenever an object of that type is required. 
// @return: an instance of a XRequest object 
XRequest.GetInstance = function() 
{ 
    if(XRequest.instance == null) 
    { 
     XRequest.instance = new XRequest(); 
    } 

    return XRequest.instance; 
} 

// @method static CreateXHR: Implments a basic factory method for creating a XMLHttpRequest object 
// @return: XMLHttp object or null 
XRequest.CreateXHR = function() 
{ 
    var xhr = null; 
    var factory = [ 
        function() { return new XMLHttpRequest(); }, 
        function() { return new ActiveXObject("Msxml2.XMLHTTP"); }, 
        function() { return new ActiveXObject("Microsoft.XMLHTTP"); } 
       ]; 

    for(var i = 0; i < factory.length; ++i) 
    { 
     var f = factory[i]; 
     xhr = f(); 
     if(xhr) 
      return xhr; 
    } 

    return null; 
} 

XRequest.prototype.SetRequestHeader = function(name, value) 
{ 
    if(this.XHR) 
    { 
     //alert(name+'|||'+value); 
     this.XHR.setRequestHeader(name, value); 
    } 
} 

XRequest.prototype.SendRequest = function(args) 
{ 
    var async = true; 
    var type = ""; 
    var url = ""; 
    var username = ""; 
    var password = ""; 
    var body = null; 
    var success = null; 
    var failure = null; 

    for(e in args) 
    { 
     switch(e) 
     { 
      case "async": 
       async = args[e]; 
       break; 

      case "type": 
       type = args[e]; 
       break; 

      case "success": 
       success = args[e]; 
       break; 
      case "failure": 
       failure = args[e]; 
       break; 

      case "url": 
       url = args[e]; 
       break; 

      case "username": 
       username = args[e]; 
       break; 

      case "password": 
       password = args[e]; 
       break; 

      case "body": 
       body = args[e]; 
       break; 
     } 
    } 

    var that = this; 
    this.XHR.onreadystatechange = function() 
     { 
      alert("readyState == " + that.XHR.readyState + " status == " + that.XHR.status); 
      if(that.XHR.readyState == 4) 
      { 
       if(that.XHR.status == 200 || that.XHR.status == 0) 
       { 
        if(success) 
         success(that.XHR); 
       } 
       else 
       { 
        if(failure) 
         failure(); 
       } 
      } 
     }; 

    this.XHR.open(type, url, async, username, password); 
    for(e in args) 
    { 
     switch(e) 
     { 
      case "setHeader": 
       var h = args[e].split(":");    
       if(h.length == 2) 
       { 
        this.SetRequestHeader(h[0], h[1]); 
       } 
       break; 
     } 
    } 
    this.XHR.send(body); 
} 
+0

Sí, ya lo he probado antes de preguntar aquí, basado en esa publicación http://lists.apple.com/archives/dashboard-dev/2006/Dec/msg00007.html, y no funcionó. – Andres

+0

"Problema en esta biblioteca ajax. Se debe llamar a XHR.setRequestHeader() después de XHR.open()" -> muchas gracias;) – daveoncode

6

Por lo general, este error se produce con el XMLHttpRequest cuando se llama al método abierto con async = true, o se dejan sin definir el parámetro asíncrono por lo que por defecto a asíncrona, y luego accede a las propiedades de estado o responseText. Esas propiedades solo están disponibles después de realizar una llamada síncrona o de que readyState esté listo (una vez que responde la llamada asíncrona). Le sugiero que primero intente con async = false, y luego cambie a que sea verdadero y use el parámetro onReadyStateChange.

+0

exactamente lo que necesitaba: comprobé el estado, pero no el de readyState. Pero es importante tener ReadyState == 4 antes de consultar cualquier otra cosa – Dmitry

+0

Señaló algo crítico y no tan obvio. Gracias. – Sebas

3

En mi caso, el error ocurrió cuando intenté acceder a xhr.statusText dentro del método xhr.onreadystatechange, sin embargo, recuperando xhr.readyState fue muy bien.

Cuestiones relacionadas