2013-02-06 16 views
6

Gram z tym XmlHttpRequest rzeczy. W niektórych samouczkach i książkach jest to funkcja onload, która jest wywoływana po zakończeniu żądania. W moim małym eksperymencie funkcja ta nigdy nie jest wywoływana. Oto mój kod:XmlHttpRequest.onload nie nazywa się

window.onload = function() { 
     var url = "http://www.google.com"; 
     var request = new XMLHttpRequest(); 


     request.onload = function() { 
      var state = this.readyState; 
      var responseCode = request.status; 
      console.log("request.onload called. readyState: " + state + "; status: " + responseCode); 

      if (state == this.DONE && responseCode == 200) { 
       var responseData = this.responseText; 
       alert("Success: " + responseData.length + " chars received."); 
      } 
     }; 

     request.error = function(e) { 
      console.log("request.error called. Error: " + e); 
     }; 

     request.onreadystatechange = function(){ 
      console.log("request.onreadystatechange called. readyState: " + this.readyState); 
     }; 

     request.open("GET", url); 
     request.send(null); 
    }; 

Testuję to w ostatnim wydaniu Firefoksa (właśnie dziś zaktualizowane). Linia dziennika w onload nigdy nie jest drukowana, a punkt przerwania ustawiony w pierwszej linii nigdy nie zostanie trafiony. Jednak funkcja onreadystatechange jest wywoływana dwa razy, a żądanie HTTP jest faktycznie wykonywane. To właśnie konsoli Firebug pokazuje:

request.onreadystatechange called. readyState: 1 
    GET http://www.google.com/ 302 Found 174ms 
    request.onreadystatechange called. readyState: 4 
    NS_ERROR_FAILURE: Failure 
     request.send(null); 

Jest błąd w linii send. Próbowałem zmienić go na request.send() z identycznym wynikiem.

Początkowo myślałem, że to może być przeglądarka próbująca zapobiec XSS, więc przeniosłem swoją stronę sterownika html do instancji Tomcat w mojej maszynie dev, ale wynik jest taki sam.

Czy można zagwarantować tę funkcję? Jak już wspomniano powyżej, jest wspólna być postrzegane w większości tutoriali, ale z drugiej strony w W3C spec page dalej, fragment hello world wykorzystuje onreadystatechange zamiast:

function processData(data) { 
     // taking care of data 
    } 

    function handler() { 
     if(this.readyState == this.DONE) { 
     if(this.status == 200 && 
      this.responseXML != null && 
      this.responseXML.getElementById('test').textContent) { 
      // success! 
      processData(this.responseXML.getElementById('test').textContent); 
      return; 
     } 
     // something went wrong 
     processData(null); 
     } 
    } 

    var client = new XMLHttpRequest(); 
    client.onreadystatechange = handler; 
    client.open("GET", "unicorn.xml"); 
    client.send(); 

Sprawdza readyState == this.DONE. DONE ma wartość 4, co widzę w dzienniku. Więc jeśli był to problem związany z XSS, a przeglądarka uniemożliwiała mi nawiązanie połączenia z inną domeną, to dlaczego nawiązano połączenie i odebrano status DONE ???

PS: Tak, wiem, że istnieją potężne biblioteki, które mogą to łatwo zrobić, ale nadal jestem noobem JavaScript, więc najpierw chciałbym zrozumieć niski poziom.


UPDATE:
Zmieniłem adres URL do jednego w mojej domenie (localhost), a błąd zniknął ale funkcja onload nadal nie miano. Testowany w IE8 i nie działa. Testowane w Chrome i działa. Jak to?


UPDATE 2:
Testowany ponownie w Firefoksie, a teraz działa. Prawdopodobnie stara strona była nadal przechowywana w pamięci podręcznej, dlatego nie mogłem tego natychmiast zauważyć. Nadal nieudane w IE8, spróbuję przetestować go w nowszej wersji.

+0

Należy pamiętać, że jQuery rozwiązuje że już. Nawet jeśli nie chcesz go używać, możesz przestudiować jego kod. –

+0

Tak właśnie mi powiedzieli webdevowie w pracy. Bez problemu użyłbym go w prawdziwym projekcie. Który plik źródłowy powinienem wyszukać? –

+0

jQuery jest zawijany w pliku. Nie polecam używania wersji minified, ponieważ jest trudniej ją odczytać. Poszukaj metody 'ajax', kopiuj w razie potrzeby. –

Odpowiedz

7

Wygląda na to, że był to problem XSS, a Firefox blokował wywołanie onload. Nie mogę jeszcze zrozumieć, dlaczego żądanie sieci http zostało faktycznie wykonane, a onreadystatechange został wywołany z DONE readyState.

Zmieniłem adres URL na inny w tej samej domenie, a teraz działa on w przeglądarce Firefox (po niektórych fałszywych próbach związanych z pamięcią podręczną) oraz w przeglądarce Chrome. Nadal nie działa w IE8, pomimo że official docs twierdzi, że jest obsługiwany. Znalazłem this SO answer, który stwierdza inaczej. Wygląda na to, że funkcja onload jest bardziej nowoczesną metodą wygodną, ​​a starym sposobem sprawdzania wyniku jest użycie onreadystatechange.

Sądzę, że przyjmuję tę odpowiedź jako rozwiązanie, chyba że dostarczono bardziej szczegółową odpowiedź.

+3

Szukałem tego samego problemu przez pewien czas. Chciałbym wiedzieć, czy coś nowego znaleziono. –

0

IE ma inną metodę tworzenia xmlhttprequest.

function createCORSRequest(method, url) { 
    var xhr = new XMLHttpRequest(); 
    if ("withCredentials" in xhr) { 

    // Check if the XMLHttpRequest object has a "withCredentials" property. 
    // "withCredentials" only exists on XMLHTTPRequest2 objects. 
    xhr.open(method, url, true); 

    } else if (typeof XDomainRequest != "undefined") { 

    // Otherwise, check if XDomainRequest. 
    // XDomainRequest only exists in IE, and is IE's way of making CORS requests. 
    xhr = new XDomainRequest(); 
    xhr.open(method, url); 

    } else { 

    // Otherwise, CORS is not supported by the browser. 
    xhr = null; 

    } 
    return xhr; 
}; 

sam ten artykuł: https://www.html5rocks.com/en/tutorials/cors/