2010-03-01 4 views
16

Я разрабатываю простой вспомогательный класс для отправки запросов с использованием XmlHttpRequest (код ниже). Но я не могу заставить его работать. В Google Chrome, например, я получаю ошибку INVALID_STATE_ERR: DOM Exception 11 и в других браузерах я получить статус == 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); 
} 

Пример использования:

<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

Я не могу себе представить, почему вы хотели бы написать что-то подобное, за исключением, может быть, для удовольствия. Это не отвечает на ваш вопрос, но я советую вам сделать цикл «for» be: «for (var e in args) ...» – Pointy

+0

Это не для удовольствия. Это будет работать во встроенном браузере, и код очень часто использует HTTP-запросы, поэтому я помещаю его в класс, чтобы упростить его использование. Кроме того, код еще не завершен! – Andres

+2

Ну почему бы вам просто не использовать одну из многих, много открытых исходных фреймворков, которые уже предоставляют такую ​​функциональность? У них уже есть ошибки, и проблемы с кросс-браузером решены. – Pointy

ответ

9

Несмотря на это, вы можете упростить метод SendRequest путем создания подмешать вместо того, чтобы использовать гигантский 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); 
}; 

быть также осторожным: существующие for..in петли имеют две различные задачи:

  1. Вы не используете var и вызывая глобальное быть создано: for (e in args) должен быть for (var e in args)
  2. Всякий раз, когда вы используете for..in, вы всегда должны проверять, чтобы каждая клавиша была прямым членом объекта, а не что-то ненаследственно наследуемое через прототип

.

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

Проблема в этом АЯКС библиотеке ,

XHR.setRequestHeader() следует называть после 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

Да, я уже пробовал это, прежде чем спрашивать здесь, основываясь на этом сообщении http://lists.apple.com/archives/dashboard-dev/2006/Dec/msg00007.html и не работал. – Andres

+0

«Проблема в этой библиотеке ajax. XHR.setRequestHeader() должен быть вызван после XHR.open()» -> спасибо большое;) – daveoncode

6

Обычно эта ошибка возникает с XMLHttpRequest при вызове метода с открытым асинхронном = истинным или оставить параметр асинхронного неопределенный так он по умолчанию асинхронного, а затем доступ к свойствам состояния или responseText. Эти свойства доступны только после синхронного вызова или готовности ReadyState (после ответа асинхронного вызова). Я предлагаю вам сначала попробовать с async = false, а затем переключиться на его истинность и использовать onReadyStateChange.

+0

именно то, что мне нужно: я проверил статус, но не для readyState. Но важно иметь readyState == 4, прежде чем проверять что-либо еще. – Dmitry

+0

Указывает на что-то важное и не столь очевидное. Спасибо. – Sebas

3

В моем случае произошла ошибка, когда я попытался получить доступ к xhr.statusText в пределах метода xhr.onreadystatechange, однако получение xhr.readyState прошло очень хорошо.

Смежные вопросы