sobota, 6 czerwca 2015

[AJAX] Podstawy Ajax-a i obiekt XMLHttpRequest

TRUE
7129893189936219737
AJAX, czyli Asynchronous JavaScript and XML to metoda pozwalająca na asynchroniczne ładowanie elementów strony bez potrzeby jej odświeżania. Metodą tę spopularyzowała firma Google, dodając do swojej wyszukiwarki funkcjonalność opartą na podpowiadaniu zapytania. Obecnie AJAX wykorzystywany jest praktycznie wszędzie. Połączenie wykonywane przez AJAX polega na wysłaniu żądania z poziomu strony je implementującej, a następnie na odebraniu odpowiedzi na to żądanie od zewnętrznej strony/skryptu. Połączenie takie odbywa się w tle, za pomocą sporządzenia przez przeglądarkę obiektu o nazwie XMLHttpRequest i następnie za pomocą tego obiektu następuje komunikacja. W artykule tym nauczymy się tworzyć taki obiekt, a następnie za jego pomocą łączyć się z zewnętrznymi źródłami danych. AJAX-a można używać "na czysto" operując bezpośrednio na obiekcie XMLHttpRequest, można też skorzystać z gotowych frameworków, takich jak np. jQuery, które automatyzują kilka aspektów połączenia. Przesyłanie danych ajaxowych za pomocą metod dostępnych w jQuery opiszę jednak w innym artykule, tutaj zobaczymy jak obiekt XMLHttpRequest wygląda i działa "od środka", operując na nim bezpośrednio, bez użycia zewnętrznych frameworków.

Zasada działania AJAX-a

Na samym początku tworzony jest obiekt XMLHttpRequest. Podczas tworzenia takiego obiektu definiujemy dla niego funkcje zwrotną, która zostanie wywołana podczas procedury połączenia i która obsłuży odebrane przez AJAX dane. Następnie - żądanie (request) utworzone za pomocą obiektu XMLHttpRequest wysyłane jest do zewnętrznego pliku. Plik ten następnie reaguje na żądanie odsyłając odpowiedź (resposne), w której zwraca odpowiednie dane. Odpowiedź taka  przesyłana jest z powrotem do naszego obiektu, gdzie zostaje przetworzona przez funkcję, którą zdefiniowaliśmy podczas tworzenia obiektu XMLHttpRequest. Cała ta procedura odbywa się "w tle". Z otrzymanymi danymi następnie możemy już zrobić co tylko chcemy.

źródło obrazka: http://www.w3schools.com/ajax/ajax.gif



Kody stanu - readyState

Podczas połączenia za pomocą AJAX-a operować będziemy stanami (statusami) takiego połączenia. Kodów stanu jest 5, a każdy z nich odpowiada za określenie innego stanu w jakim znajduje się obecnie nasze połączenie.
Nasze połaczenie znajduje się w innym stanie podczas próby połączenia, jeszcze w innym podczas udanego odebrania danych, jeszcze w innym podczas wystąpienia błędu. Na podstawie analizy tego stanu możemy wywoływać odpowiednie akcje, odpowiednie do tego co akurat dzieje się z naszym połączeniem. I tak np. podczas odebrania danych wywołamy funkcję, która obsłuży odebrane dane, a w przypadku np. błędu wywołamy inną funkcję, odpowiadającą za wyświetlenie komunikatu o problemie. Stan połączenia określany jest za pomocą wartości liczbowych od 0 do 4.

Obiekt XMLHttpRequest tworzymy w Javascript standardowo:
[code]var xmlhttp = new XMLHttpRequest();[/code]

XMLHttpRequest posiada 3 podstawowe własności, z których będziemy korzystać podczas pracy:

  • readyState - przechowuje (jako wartość liczbową od 0 do 4) obecny stan obiektu. Poniżej możliwe wartości:
    0 - żadanie nie zostało jeszcze przygotowane
    1 - połączenie z serwerm zostało wykonane poprawnie
    2 - otrzymano odpowiedź od serwera
    3 - odpowiedź od serwera jest obecnie przetwarzana
    4 - wykonanie żądania udalo się poprawnie, odpowiedź od serwera została w całości odebrana

  • onreadystatechange - przechowuje funkcję zwrotną (callback), która wywoływana jest w momencie każdej zmiany stanu w readyState. Funkcja taka wywoływana jest automatycznie podczas kazdego wystąpienia tego zdarzenia.

  • status - przechowuje status połączenia odebrany od serwera, może zawierać 2 wartości:
    200: "OK" - gdy zasób, do którego wysyłamy żądanie istnieje
    404: Page not found - gdy serwer zwraca nam, że zasób nie istnieje

Aby przygotować obiekt XMLHttpRequest musimy po pierwsze zdefiniować dla zdarzenia onreadystatechange funkcję, która na podstawie analizy readyState wywoła odpowiednie akcje.
Jak już zostało napisane - funkcja taka wykona się podczas każdego wystąpienia tego zdarzenia (eventu) - czyli za każdym razem, gdy stan obiektu zapisany w readyState zmieni swoją wartość.

Przykładowa definicja może więc wyglądać tak:
[code]
var xmlhttp = new XMLHttpRequest();
xmlhttp.onreadystatechange = function()
{
  if(xmlhttp.readyState == 4 && xmlhttp.status == 200)
  {
    alert('Odebrano odpowiedź z serwera');
  }

  if(xmlhttp.status == 404)
  {
    alert('Problem - serwer wzrócił błąd 404');
  }
}
[/code]
W pierwszym bloku if sprawdzamy, czy stan połączenia równa się 4, czyli czy odebrano wszystkie dane oraz czy status połączenia równa się 200 "OK".
Jeśli tak, wyświetlamy komunikat, że wszystko się udało.
W drugim bloku if definiujemy, że jeśli odpowiedzią serwera będzie kod 404 Not Found, to wyświetlamy komunikat o błędzie.

Przygotowanie żądania

Każde żądanie (request), jakie chcemy obsłużyć za pomocą XMLHttpRequest musimy najpierw zdefiniować, a następnie je wysłać. Do zdefiniowania naszego żądania służy metoda open(), natomiast do jego wysłania - metoda send().

Żądanie przygotowujemy w następujący sposób:
[code]open(method, url, async);[/code]
gdzie:

  • method - w tym argumencie podajemy sposób wykonania ządania, może to być GET lub POST
  • url - adres, z którym chcemy się połączyć
  • async - w ostatnim parametrze określamy, czy chcemy połączyc się asynchronicznie, podajemy true, lub false.


Tak przygotowane żądanie wysyłamy następnie metodą send().

Przykładowe żądanie może wyglądać więc tak:
[code]
var xmlhttp = new XMLHttpRequest();
xmlhttp.open("GET", "ajax.txt", true);
xmlhttp.send();
[/code]
Spowoduje to wysłanie żądania metodą GET do pliku ajax.txt.
Żądanie zostanie wysłane asynchronicznie, a więc nie będzie blokować wykonania żadnych innych żądań, aż do wykonania swojego.

Testujemy

Aby przetestować działanie AJAX-a utwórzmy sobie 2 pliki:

  • index.html
  • ajax.txt

Spróbujemy teraz z poziomu pliku index.html wczytać zawartość pliku ajax.txt
W pliku index.html wpiszmy taką treść:
[code]
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Ajax Test</title>
</head>

<body>
<script>
  var xmlhttp = new XMLHttpRequest();
  xmlhttp.open("GET", "ajax.txt", true);
  xmlhttp.send();
</script>
</body>
</html>
[/code]
Natomiast w pliku ajax.txt, wpiszmy np tekst:
[code]Hello World![/code]

Dodajmy teraz do naszego skryptu definicję funkcji, która obsłuży nam nasze żądanie.
[code]
<script>
  var xmlhttp = new XMLHttpRequest();
  xmlhttp.onreadystatechange = function()
  {
    if(xmlhttp.readyState == 4 && xmlhttp.status == 200)
    {
      alert('Odebrano odpowiedz z serwera');
    }
 
    if(xmlhttp.status == 404)
    {
      alert('Problem - serwer wzrocil bład 404');
    }
  };

  xmlhttp.open("GET", "ajax.txt", true);
  xmlhttp.send();
</script>
[/code]
Zobaczmy teraz, co się stanie:



Jak widać udało się. Za pomocą AJAXA został wczytany plik ajax.txt i wyświetlony został komunikat za pomocą funkcji alert().
A jak teraz wyświetlić odebrane z pliku ajax.txt dane?
Służą do tego dwie kolejne własności obiektu XMLHttpRequest - responseText i responseXML.
Pierwsza z nich pobiera wczytaną zawartość do stringa jako tekst, druga pobiera dane w formacie XML.

Dane jako string - responseText

Na początek wyświetlimy sobie odebrane dane jako zwykły tekst, ale w tym celu przebudujmy nasz plik index.html, tak aby odpowiedź wczytała nam się do DIV-a o identyfikatorze response.
Dodamy sobie też buttona, który wczyta nam dane ajax-em dopiero po kliknięciu na niego. Zamkniemy zatem nasz kod w oddzielnej funkcji runAjax(), którą wywołamy dopiero po kliknięciu na przycisk. Funkcja następnie po wczytaniu danych podmieni zawartość DIV-a z id response za pomocą document.getElementById("response").innerHTML.
[code]
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Ajax Test</title>
<style>#response { border:2px solid #000; padding: 5px }</style>
</head>

<body>
<div id="response">AJAX</div>
<input type="button" value="Load Ajax" onclick="runAjax()" />

<script>
function runAjax()
{
  var xmlhttp = new XMLHttpRequest(); // tworzymy obiekt XMLHttpRequest
  // definiujemy funkcję callback dla zdarzenia onreadystatechange
  xmlhttp.onreadystatechange = function()
  {
    if(xmlhttp.readyState == 4 && xmlhttp.status == 200)
    {
      // jeśli otrzymamy odpowiedź, to wpisujemy ją do DIV-a o id=response
      document.getElementById("response").innerHTML = xmlhttp.responseText;
    }
  };

  // tworzymy żądanie i wysyłamy
  xmlhttp.open("GET", "ajax.txt", true);
  xmlhttp.send();
}
</script>
</body>
</html>
[/code]
Zobaczmy teraz co się stanie. Po kliknięciu na przycisk, wczytywana jest do naszego DIV-a zawartość z pliku ajax.txt:



AJAX i PHP

Wczytaliśmy do tej pory prościutki plik tekstowy i wiemy już jak wygląda użycie obiektu XMLHttpRequest.
Zobaczmy teraz jak może wyglądać komunikacja za pomocą AJAX-a z wykorzystaniem PHP. Aby tego dokonać, utwórzmy sobie na serwerze folder testowy, np. /ajax, tak, aby po wejściu na:
[code]http://localhost/ajax/[/code]
wyświetlił nam się plik index.php, który tam zaraz umieścimy. Stwórzmy więc w naszym testowym folderze 2 pliki:

  • index.php
  • ajax.php

Wyślemy teraz z pliku index.php za pomocą AJAX-a żadanie do pliku ajax.php i zobaczymy co uzyskamy w odpowiedzi.
W parametrze żądania będziemy podawać liczbową wartość miesiąca - np. 3, natomiast skrypt w pliku ajax.php będzie miał za zadanie zwrócić nam jego nazwę (np. marzec).

/ajax/ajax.php
Przygotujmy najpierw plik ajax.php. Podamy mu tablicę z nazwami miesięcy. Na podstawie otrzymanej wartości podawanej jako parametr w zmiennej GET będzie zwracał odpowiednią nazwę miesiąca.
Plik niech wygląda tak:
[code]
<?php
// ajax.php

$miesiac = intval($_GET['miesiac']);

$nazwa[1] = 'styczeń';
$nazwa[2] = 'luty';
$nazwa[3] = 'marzec';
$nazwa[4] = 'kwiecień';
$nazwa[5] = 'maj';
$nazwa[6] = 'czerwiec';
$nazwa[7] = 'lipiec';
$nazwa[8] = 'sierpień';
$nazwa[9] = 'wrzesień';
$nazwa[10] = 'październik';
$nazwa[11] = 'listopad';
$nazwa[12] = 'grudzień';

echo $nazwa[$miesiac];
?>
[/code]


/ajax/index.php
Plik index.php ze skryptem ajaxowym niech wygląda natomiast tak:
[code]
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Ajax Test</title>
<style>#response { border:2px solid #000; padding: 5px }</style>
</head>

<body>
<div id="response">AJAX</div>
<input type="button" value="Load Ajax" onclick="runAjax()" />

<script>
function runAjax()
{
  var xmlhttp = new XMLHttpRequest(); // tworzymy obiekt XMLHttpRequest

  // definiujemy funkcję callback dla zdarzenia onreadystatechange
  xmlhttp.onreadystatechange = function()
  {
    if(xmlhttp.readyState == 4 && xmlhttp.status == 200)
    {
      // jeśli otrzymamy odpowiedź, to wpisujemy ją do DIV-a o id=response
      document.getElementById("response").innerHTML = xmlhttp.responseText;
    }
  };

  // tworzymy żądanie i wysyłamy
  xmlhttp.open("GET", "ajax.php?miesiac=4", true);
  xmlhttp.send();
}
</script>
</body>
</html>
[/code]
Wejdźmy teraz na http://localhost/ajax/index.php i zobaczmy co się stanie.
Po kliknięciu na przycisk powinniśmy połączyć się poprzez AJAX ze skryptem ajax.php, podając mu w parametrze ?miesiac=4.
Następnie skrypt w PHP powinien zwrócić odpowiedni dla wartości podanej w parametrze $_GET['miesiac'] element z tablicy. Finalnie w naszym DIV-ie powinna wylądować nazwa miesiąca, w tym przypadku kwiecień:



Voila! Dokonaliśmy właśnie pierwszej, prostej komunikacji pomiędzy PHP i Javascriptem za pomocą AJAX-a.

Żądania POST

Większe ilości danych, a także takie, które są pobierane z formularza powinniśmy wysyłać metodą POST. Jak pamiętamy, metoda open(), służąca do przygotowania żądania pozwala na wybór pomiędzy metodą wysłania żądania (GET lub POST). Sprawdźmy teraz jak wygląda sprawa z metodą POST. W przypadku wysyłania żądania typu POST metoda send() może przyjąć jako parametr ciąg z wartościami zmiennych jakie zostaną wysłane POST-em.

Przykładowo, wywołanie:
[code]send('zmienna1=aaaa&zmienna2=bbbb');[/code]
wyśle wraz z żądaniem dwie zmienne: zmienna1 i zmienna2, które to zmienne zostaną wysłane jako zmienne POST. Możemy w taki sposób np. wysyłać poprzez AJAX dane z formularza, co za chwilę uczynimy.
Przyjrzyjmy się jednak jeszcze jednej metodzie obiektu XMLHttpRequest - setRequestHeader().

Metoda setRequestHeader()

Obiekt XMLHttpRequest pozwala na ustawienie dowolnego nagłówka HTTP podczas wysyłania żądania.
Służy do tego metoda:
[code]xmlhttp.setRequestHeader(header, value);[/code]
gdzie:

  • header - nazwa nagłówka, np. Content-Type
  • value - wartość nagłówka

W przypadku wysyłania danych z formularza (metodą POST) ustawić będziemy musieli nagłówek Content-Type wskazujący na formularz.
Zrobimy to następująco:
[code]xmlhttp.setRequestHeader("Content-type","application/x-www-form-urlencoded");[/code]

Wróćmy jednak do samego żądania. Przetestujemy teraz wysłanie prostego formularza metodą POST. Przerobimy nieco nasz poprzedni kod, tak aby można było podać numer miesiąca w polu input, a następnie wpisaną wartość wyślemy jako zmienną typu POST. Zmodyfikujmy zawartość pliku index.php na:
[code]
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Ajax Test</title>
<style>#response { border:2px solid #000; padding: 5px }</style>
</head>

<body>
<div id="response">AJAX</div>
<form method="post">
Numer miesiąca: <input type="text" name="miesiac" id="input_numer" /><input type="button" value="Wyślij" onclick="runAjax()" />
</form>

<script>
function runAjax()
{
  var numer =  document.getElementById("input_numer").value; // pobieramy wartość inputa
  var xmlhttp = new XMLHttpRequest(); // tworzymy obiekt XMLHttpRequest

  // definiujemy funkcję callback dla zdarzenia onreadystatechange
  xmlhttp.onreadystatechange = function()
  {
    if(xmlhttp.readyState == 4 && xmlhttp.status == 200)
    {
      // jeśli otrzymamy odpowiedź, to wpisujemy ją do DIV-a o id=response
      document.getElementById("response").innerHTML = xmlhttp.responseText;
    }
  };

  // tworzymy żądanie i wysyłamy
  xmlhttp.open("POST", "ajax.php", true);
  xmlhttp.setRequestHeader("Content-type","application/x-www-form-urlencoded");
  xmlhttp.send("miesiac=" + numer);
}
</script>
</body>
</html>
[/code]
W pliku ajax.php zmieńmy natomiast linijkę odpowiadającą za pobranie zmiennej z:
[code]$miesiac = intval($_GET['miesiac']);[/code]
na
[code]$miesiac = intval($_POST['miesiac']);[/code]

I sprawdźmy teraz jak to wszystko działa.
Po wpisaniu numeru miesiąca i kliknięciu na Wyślij wartość pobrana z pola input zostaje wysłana POST-em do pliku ajax.php, następnie tak jak poprzednio zwrócona zostaje pełna nazwa miesiąca:



Przy przesyłaniu danych metodą POST pamiętajmy zawsze o umieszczaniu ich w parametrze send() oraz o ustawianiu nagłówka Content-Type na wartość application/x-www-form-urlencoded.

Umiemy już w tej chwili przesyłać proste dane za pomocą metod GET i POST, czas przyjrzeć się danym pobieranym w formacie XML.

Dane jako XML - responseXML

Za pomocą AJAX-a zazwyzcaj nie przesyła się tak prostych danych jakie przesyłaliśmy powyżej, lecz bardziej złożone struktury, z większą ilością elementów. Dane takie przesyłane są albo tekstem w formacie JSON, albo formatem XML. Przyjrzyjmy się tej drugiej opcji. Odbiór takich danych różni się od odebrania danych w postaci tekstu. Na odebranych jako XML danych możemy pracować bezpośrednio, odwołując się do zawartych w nich znacznikach i ich wartościach jak do drzewa DOM.

Przypomnijmy, że odpowiedź w formacie XML odbieramy za pomocą:
[code]var xml = xmlhttp.responseXML;[/code]

Przygotujmy sobie testowy plik XML zawierający np. listę kilku książek wraz z ich autorami:
[code]
<?xml version="1.0" encoding="utf-8"?>
<books>
  <book>
    <title>Pan Tadeusz</title>
    <author>Adam Mickiewicz</author>
  </book>

  <book>
    <title>Hobbit</title>
    <author>J.R.R. Tolkien</author>
  </book>

  <book>
    <title>Solaris</title>
    <author>Stanisław Lem</author>
  </book>
</books>
[/code]
Plik taki zapiszmy pod nazwą np. books.xml

Teraz zobaczmy jak dostać się do tych danych za pomocą AJAX-a.
Zmodyfikujmy nasz plik index.php na nastepujący:
[code]
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Ajax Test</title>
<style>#response { border:2px solid #000; padding: 5px }</style>
</head>

<body>
<div id="response">AJAX</div>
<input type="button" value="getBooks" onclick="runAjax()" />


<script>
function runAjax()
{
  var xmlhttp = new XMLHttpRequest(); // tworzymy obiekt XMLHttpRequest
  var i, tag;

  // definiujemy funkcję callback dla zdarzenia onreadystatechange
  xmlhttp.onreadystatechange = function()
  {
    if(xmlhttp.readyState == 4 && xmlhttp.status == 200)
    {
      // rozpoczynamy tabelę:
      var txt = '<table border="1"><tr><th>title</th><th>author</th></tr>';    
   
      var xml = xmlhttp.responseXML; // odbieramy dane jako XML
      /* objekt xml zawiera w tym momencie calą strukture dokumentu books.xml */      
   
      // pobieramy elementy <book> do obiektu books
      var books = xmlhttp.responseXML.documentElement.getElementsByTagName("book");
   
      // liczymy elementy <book>
      var c = books.length;
   
      // przelatujemy pętlą for po elementach <book>
      for(i = 0; i < c; i++)
      {
        // rozpoczynamy nowy wiersz tabeli
        txt = txt + '<tr>';
     
        // pobieramy tytuł do kolumny tabeli
        tag = books[i].getElementsByTagName("title");
        txt = txt + '<td>' + tag[0].firstChild.nodeValue + '</td>';
     
        // pobieramy autora do kolumny tabeli
        tag = books[i].getElementsByTagName("author");
        txt = txt + '<td>' + tag[0].firstChild.nodeValue + '</td>';
     
        // kończymy wiersz tabeli
        txt = txt + '</tr>';
      }    
       
       // kończymy tabelę
       txt = txt + '</table>';
   
      // podrzucamy tabelę do DIV-a
      document.getElementById("response").innerHTML = txt;
    }
  };

  // tworzymy żądanie i wysyłamy
  xmlhttp.open("GET", "books.xml", true);
  xmlhttp.send();
}
</script>
</body>
</html>
[/code]
I zobaczmy rezultat:

Podsumowanie

Jak widać, wszystkie elementy pobrane z XML-a wyświetliły się nam w tabelce. Ta tabelka to naturalnie jedynie przykład wykorzystania AJAX-a w przetwarzaniu danych XML. W praktyce w miejscu tym przesłalibyśmy treść odpowiedzi zawierającą w sobie wiele elementów, które następnie przypisalibyśmy do odpowiednich zmiennych i przetworzyli. Na tym właśnie polega praca z AJAX-em i danymi w XML. Dane w XML-u bardzo łatwo można sporządzac np. za pomocą PHP. następnie tak spreparowane dane, w postaci wygenerowanego XML-a odsyłamy AJAX-em do strony, po czym dalej przetwarzamy za pomocą Javascriptu. Nic tutaj nas nie ogranicza, a komunikacja odbywa się w obie strony. Możliwości wykorzystania AJAX-a są naprawdę ogromne.

W następnych artykułach przeanalizujemy kilka praktycznych zastosować komunikacji AJAX <> PHP oraz nauczymy się jak korzystać z AJAX-a za pomocą biblioteki jQuery. Na razie, tytułem wprowadzenia umiemy już pracować z obiektem XMlHttpRequest i znamy podstawy jego użycia w praktyce, co myślę, że na wstępie powinno wystarczyć. Do następnego!

2 komentarze:

  1. Merhaba, Site üye olan kullanıcıların üye aktif etmek için mail gelen aktivasyon url spam düşüyor neden olabilir.


    Site : https://resimyukle.com.tr

    OdpowiedzUsuń
  2. Bardzo ciekawe, ale dosyć trudne, jeśli nie wiemy jak i nie mamy doświadczenia.

    OdpowiedzUsuń

Masz sugestię? Znalazłeś błąd? Napisz komentarz! :)

webmaester.pl - profesjonalne projektowanie WWW i webaplikacji
webmaester.pl - profesjonalne projektowanie WWW i webaplikacji