[Ajax] Obiekt XMLHttpRequest
Poniższy artykuł będzie o wykorzystaniu obiektu XMLHttpRequest do wysyłania asynchronicznych żądań ze strony www do serwera.
Jeśli nie wiesz, czym jest Ajax, warto przeczytać:
Co na początek?
Aby móc uruchomić przykłady zawarte w tym artykule potrzebujesz:
- serwera www [np. Wamp]
- przeglądarki www [np. Firefox]
- przydatny może być edytor [np. Geany]
- około 10 minut
Jeśli chciałbyś, aby Twoje skrypty wykorzystujące Ajax działały również po IE6, warto zapoznać się z artykułem o odpowiedniej łacie:
Obiekt XMLHttpRequest
Według specyfikacji w3c obiekt ten posiada takie pola:
XMLHttpRequest = {
onreadystatechange;
open(string method, string url, boolean async);
setRequestHeader(string header, string value);
send(mixed data);
abort();
status;
statusText;
getResponseHeader(string header);
getAllResponseHeaders();
responseText;
responseXML;
};
Niektóre z nich mogą być przeciążane, ale to można doczytać w dokumentacji.
Najprostszy działający przykład
Ponieważ chcę pokazać istotę Ajax wszystkie przykłady będą operować na zwracanych danych typu 'plain-text'. Istnieje także możliwość operowania na XML, poprzez `responseXML'. Temat ten poruszyłem we wpisie o XML. Warto także zapoznać się z (moim zdaniem) lepszym formatem dla Ajaksa - JSON.
Kod PHP (działający po stronie serwera):
<?php echo "Witaj świecie!"; ?>
Zapisz ten kod do pliku 'ajax.php'.
Kod strony (JS + HTML):
<html>
<head>
<title>Przykład Ajax</title>
<meta http-equiv="content-type" content="text/html;charset=utf-8" />
<script type="text/javascript">
function ajaxTest()
{
var client = new XMLHttpRequest();
client.open('POST', 'ajax.php', false);
client.send(null); // ważna linia
alert(client.responseText);
}
</script>
</head>
<body><div onclick="ajaxTest()" id="content">Kliknij mnie</div></body>
</html>
Powyższy kod pozwala na wyświetlenie w alercie teksu uzyskanego z serwera. Jak widać wszystko, co zostanie wyświetlone w skrypcie po stronie serwera trafia do zmiennej `client.responseText'.
Był to przykład na synchroniczne żądanie Ajax. Synchroniczne, czyli takie, w którym w linii oznaczonej komentarzem "ważna linia" będzie czekał na odpowiedź. Metoda ta jest polecana tylko w sytuacjach, kiedy musimy być pewni, w jakiej kolejności zostaną wykonane żądania.
Częściej wykorzystuje się żądania asynchroniczne, o który mowa niżej.
Żądania asynchroniczne
W przypadku żądań asynchronicznych, skrypt nie wstrzyma działania strony. Strona będzie działać normalnie, a w tle będzie obsługiwany Ajax. Wymagane są do tego tzw. funkcje callback. Zobaczmy przykład (w skrypcie 'ajax.php' nic się nie zmienia).
<html>
<head>
<title>Przykład Ajax</title>
<meta http-equiv="content-type" content="text/html;charset=utf-8" />
<script type="text/javascript">
function ajaxTest()
{
var client = new XMLHttpRequest();
client.open('POST', 'ajax.php', true); // asynchronicznie
client.send(null);
// zdefiniuj callback
client.onreadystatechange = function()
{
// 200 = OK, 4 = odczytano, tu: this = client
if (200 === this.status && 4 === this.readyState)
{
alert('status: ' + this.statusText + '\n' +
this.responseText);
}
}
}
</script>
</head>
<body><div onclick="ajaxTest()" id="content">Kliknij mnie</div></body>
</html>
Co zmieniło się w porównaniu z poprzednim kodem?
client.open('POST', 'ajax.php', true);
Ostatni parametr ustawiony na true oznacza: "żądanie asynchroniczne".
Dodatkowo przypisaliśmy funkcję obsługującą zdarzenie readystatechange:
client.onreadystatechange = function() { ... }
Funkcja ta będzie wywoływana do obsługi wyniku zwróconego przez serwer.
Dziwne kody?
Czy są tajemnicze 200 oraz 4 z listingu? Już tłumaczę. Pole XMLHttpRequest.readyState może przyjmować wartości:
0 - nieustawiony 1 - otwarty 2 - otrzymano nagłówki 3 - ładowanie 4 - odczytano
Skoro chcieliśmy odczytać jakieś dane sprawdzamy, czy już jest wartość 4. Nie spotkałem się z przypadkiem, w którym upragnionym stanem byłby inny - chyba, że dla przykładu akademickiego.
A czymże jest 200? Jest to kod HTTP. 200 oznacza "wszystko w porządku" - a przecież tego chcemy.
Inne, często spotykane kody:
- 404 - brak strony
- 500 - błąd serwera
- zobacz pełną listę kodów odpowiedzi HTTP
W pozostałych przykładach, będę korzystał z żądań asynchronicznych.
Przesyłanie danych na serwer
Najczęściej występuje potrzeba wysłania danych na serwer. Jak to zrobić?
Zmieńmy kod 'ajax.php':
<?php echo "Wynik: " . (intval($_POST['n']) + intval($_POST['k'])); ?>
W kodzie JS też potrzebne są zmiany:
<html>
<head>
<title>Przykład Ajax</title>
<meta http-equiv="content-type" content="text/html;charset=utf-8" />
<script type="text/javascript">
function ajaxTest()
{
var client = new XMLHttpRequest();
client.open('POST', 'ajax.php', true); // asynchronicznie
// odpowiedni typ [aby moc wysylac dane]
client.setRequestHeader('Content-Type',
'application/x-www-form-urlencoded; charset=UTF-8');
// wyslij dane
client.send('n=2&k=3');
client.onreadystatechange = function()
{
if (200 === this.status && 4 === this.readyState)
{
alert('status: ' + this.statusText + '\n' +
this.responseText);
}
}
}
</script>
</head>
<body><div onclick="ajaxTest()" id="content">Kliknij mnie</div></body>
</html>
W wyniku powinniśmy otrzymać 5. Oczywiście można wysłać inne dane. W przypadku metody POST dane wysyłamy jako ciąg znaków przekazywanych do funkcji `send'. Ciąg znaków może zawierać wiele danych, wg schematu:
nazwa_zmiennej_1=wartość_x&nazwa_zmiennej_2=wartość_y
Przesyłane mogą być zarówno liczby, jak i ciąg znaków (dla HTTP wszystko i tak jest ciągiem znaków). Na serwerze odbieramy to identycznie jak w przypadku wysłanego formularza, a więc:
<?php echo $_POST['nazwa_zmiennej']; ?>
W przypadku metody GET jest trochę inaczej.
Przesyłanie danych za pomocą GET
Jak najprościej odróżnić metodę GET od POST? GET przesyła dane w adresie, np. example.com?zmienna=wartosc&zmienna2=wartosc. Więcej o GET można przeczytać na wikipedii.
Po stronie serwera zmieni się jedynie nazwa tablicy superglobalnej, z której odczytujemy dane POST -> GET.
<?php echo "Wynik: " . (intval($_GET['n']) + intval($_GET['k'])); ?>
W kodzie JS zmieni się też niewiele:
function ajaxTest()
{
var client = new XMLHttpRequest();
client.open('GET', 'ajax.php?n=2&k=3', true);
client.send(null);
client.onreadystatechange = function()
{
if (200 === this.status && 4 === this.readyState)
{
alert('status: ' + this.statusText + '\n' +
this.responseText);
}
}
}
Jak widać, ponownie do metody `send' przekazujemy null. Dodatkowo duże zmiany zaszły w linii:
client.open('GET', 'ajax.php?n=2&k=3', true);
Jest to zobrazowanie tego, o czym pisałem wcześniej. POST zmieniliśmy na GET, a także wszystkie zmienne przesyłane na serwer są podawane w adresie, jako parametry. Pamiętaj o oddzieleniu właściwego adresu od parametrów znakiem zapytania '?'.
Ograniczenia GET
Ilość danych przekazywanych do serwera jest ograniczona maksymalną długością adresu (długość ta zależy od ustawień serwera).
Warto przeczytać
Korzystanie na "gołego" obiektu XMLHttpRequest nie jest zbyt wygodne. Polecam zapoznanie sie z możliwymi ułatwieniami: