2010-03-01 4 views
16

Je développe une classe auxiliaire simple pour envoyer des requêtes en utilisant XmlHttpRequest (code ci-dessous). Mais je ne peux pas le faire fonctionner. Au google chrome, par exemple, je reçois l'erreur INVALID_STATE_ERR: DOM Exception 11 et les autres navigateurs, je reçois un statut == 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); 
} 

Exemple d'utilisation:

<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

Je ne peux pas m'imaginer pourquoi tu prendrais la peine d'écrire quelque chose comme ça, sauf peut-être pour t'amuser. Cela ne répond pas à votre question mais je vous conseille de faire que la boucle "for" soit: "for (var e in args) ..." – Pointy

+0

Ce n'est pas pour le fun. Cela fonctionnera dans un navigateur intégré et le code utilise beaucoup les requêtes http, c'est pourquoi je l'ai mis dans une classe pour simplifier son utilisation. En outre, le code n'est pas encore complet! – Andres

+2

Eh bien, pourquoi n'utiliseriez-vous pas l'un des nombreux frameworks open source qui fournissent déjà une telle fonctionnalité? Ils ont déjà résolu les bugs et résolu les problèmes de cross-browser. – Pointy

Répondre

9

Peu importe, vous pouvez simplifier votre méthode SendRequest en créant un mixin au lieu d'utiliser un switch géant.

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); 
}; 

Aussi soyez prudent: vos for..in boucles existantes ont deux problèmes distincts:

  1. Vous n'êtes pas à l'aide var et provoquant une approche globale à créer: for (e in args) devrait être for (var e in args)
  2. Chaque fois que vous utilisez for..in, vous devriez toujours vérifier pour s'assurer que chaque clé est un membre direct de l'objet, et non quelque chose hérité par inadvertance à travers le prototype

.

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

problème dans cette bibliothèque ajax .

XHR.setRequestHeader() doit être appelé après 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

Oui, je l'ai déjà essayé avant de demander ici, sur la base de ce post http://lists.apple.com/archives/dashboard-dev/2006/Dec/msg00007.html, et n'a pas fonctionné. – Andres

+0

"Problème dans cette bibliothèque ajax XHR.setRequestHeader() doit être appelé après XHR.open()" -> merci beaucoup;) – daveoncode

6

général, cette erreur se produit avec le XMLHttpRequest lorsque vous appelez la méthode ouverte avec async = true, ou vous laissez le paramètre async non défini donc sa valeur par défaut asynchrone, et vous accédez aux propriétés d'état ou responseText. Ces propriétés ne sont disponibles que lorsque vous effectuez un appel synchrone ou que readyState est prêt (une fois l'appel asynchrone répondu). Je vous suggère d'essayer d'abord avec async = false, puis de passer à true et d'utiliser onReadyStateChange.

+0

exactement ce dont j'avais besoin: J'ai vérifié l'état, mais pas pour readyState. Mais il est important d'avoir readyState == 4 avant de vérifier quoi que ce soit d'autre – Dmitry

+0

A souligné quelque chose de critique et pas si évident. Je vous remercie. – Sebas

3

Dans mon cas, l'erreur est survenue quand j'ai essayé d'accéder xhr.statusText dans la méthode xhr.onreadystatechange, mais la récupération xhr.readyState est allé très bien.