AJAX
Tämä kirja perustuu W3Cn luonnokseen The XMLHttpRequest Object (2008-04-15)
AJAX eli Asynchronous JavaScript And XML (asynkroninen JavaScript ja XML) on yhdistelmä eri tekniikoita, joiden avulla voidaan siirtää tietoa asiakasohjelman (client), yleensä selain (browser), ja palvelimen (server) välillä ilman, että koko WWW-sivua täytyy ladata uudelleen.
AJAXilla voidaan luoda tavanomaisten, kokonaan yksittäisessä tietokoneessa suoritettavien, tietokoneohjelmien tapaisia sovelluksia mutta joita käytetään WWWn välityksellä. Tällöin esimerkiksi useat käyttäjät voivat käsitellä samaa tiedostoa. Lisäksi AJAXilla voidaan vähentää resurssien tarvetta suhteessa suoritettuun toimintoon, koska siirretään vain muutos ei koko sivua joka muutoksella. Data selaimen ja serverin välillä siirtyy taustalla asynkronisesti.
AJAX käyttää seuraavia tekniikoita
- JavaScript - paikallinen prosessointi
- XML - tiedon esittäminen
- XHTML - tiedon esittäminen
- CSS - tiedon ulkoasu
- DOM - sivun sisältämän datan haku
- XMLHTTPRequest-olio - datan lukemiseen ja lähettämiseen selaimen ja serverin välillä asynkronisesti
Lisäksi tarvitaan jokin palvelinpuolen ohjelmointikieli kuten
AJAX perustuu seuraaviin standardeihin
- W3C: XML 1, HTML 4, DOM 2, CSS 2, XMLHttpRequest (luonnos), HTTP 1.1. (statuskoodit: 404 etc)
- ECMA: ECMAScript 1.5. (JavaScript)
XMLHTTPRequest-objekti
muokkaaAJAX perustuu XMLHttpRequest
-olioon. Oliona sillä on ominaisuuksia ja metodeja.
Ominaisuus | Kuvaus |
---|---|
onreadystatechange | tapahtumankäsittelijä, joka kutsuu määriteltyä funktiota kun vastaus on saatu palvelimelta |
readyState | XMLHTTPRequest-objektin tila |
responseText | käsittelee haetun datan merkkijono-muotoisena |
responseXML | käsittelee haetun datan XML-muotoisena |
status | 200 kun pyynnön suoritus onnistunut 404 kun sivua ei löydy |
statusText | palauttaa statuksen merkkijonona |
readyState-ominaisuudella on viisi eri tilaa, jotka kertovat, missä vaiheessa suoritusta pyyntö on menossa. Tilat ovat
- 0 = ei ole alustettu
- 1 = yhteys muodostettu
- 2 = pyyntö vastaanotettu
- 3 = vastausta prosessoidaan
- 4 = valmis
Metodi | Kuvaus |
---|---|
abort() | keskeyttää pyynnön |
setRequestHeader("name", "value") | Lisää nimi/arvo -parin lähetettävään HTTP ylätunnisteeseen (header) |
getResponseHeader("name") | palauttaa tietyn HTTP ylätunnisteen (header) merkkijonona |
getAllResponseHeaders() | palauttaa kaikki HTTP ylätunnisteet (headers) merkkijonona |
open("method", "URL", async) | Pyynnön määritysten antaminen |
send(data) | Lähettää pyynnön. data voi olla merkkijono tai viittaus dokumenttiin
Pyynnön lähettäminen palvelimelle (parametrina lähetettävä data, mikäli käytetään POST-metodia) |
open metodilla annetaan pyynnön määrityksiä, joista kolme tärkeintä ovat
- method, jolla valitaan datan palvelimelle lähetyksen tyypiksi GET- tai POST
- URL, johon kirjoitetaan pyynnön vastaanottavan serveriskriptin suhteellinen tai absoluuttinen url-osoite
- async, jolla asetetaan asynkroninen siirto päälle (true) tai pois päältä (false)
send-metodilla lähetään pyyntö palvelimelle. Mikäli käytetään POST-tapaa välittää tieto selaimelta palvelimelle, tulee send-metodin parametriksi lähetettävä data, muutoin null.
POST ja GET
muokkaaPOST ja GET ovat kaksi erilaista tapaa siirtää tietoa selaimelta palvelimelle ja päinvastoin. Niiden käyttö eroaa hivenen toisistaan.
GET-tavalla data siirtyy URL-osoitteen mukana.
POST-tavalla data siirtyy HTTP-otsikkotietojen mukana.
Datan siirtäminen selaimen ja palvelimen välillä
muokkaaKoodi tulee XHTML-tiedoston head-osioon <script type="text/javascript"></script>-tagien väliin.
Ensiksi esitellään globaali muuttuja XMLHTTPRequest-objektille eli luodaan instanssi.
// Esitellään muuttuja XMLHTTPRequest-objektille:
var Pyynto;
Muuttuja alustetaan omassa funktiossaan.
// Alustetaan Pyynto-muuttuja
function alustaPyynto()
{
Pyynto = new XMLHttpRequest();
}
suoritaPyynto-funktioista toteutetaan joko GET- tai POST-tavalla ei molemmilla.
Määritellään funktio varsinaisen pyynnön suorittamiselle GET-tavalla.
// Käytetään GET-tapaa datan välittämiseen palvelimelle
function suoritaPyynto()
{
// Alustetaan Pyynto-muuttuja kutsumalla edellä toteutettua funktiota
alustaPyynto();
// Määritellään funktio, joka suoritetaan, kun vastaus palvelimelta on saapunut
Pyynto.onreadystatechange = kasitteleVastaus; // HUOM: funktion nimi ilman sukeita
// Käytetään GET-tapaa datan lähettämiseen asynkronisesti
// palvelimelle serveriskripti.php-nimiselle skriptille
Pyynto.open("GET", "serveriskripti.php?nimi=Arvo", true);
// Lähetetään pyyntö palvelimelle
Pyynto.send(null);
}
Määritellään funktio varsinaisen pyynnön suorittamiselle POSP-tavalla.
// Käytetään POST-tapaa data välittämiseen palvelimelle
function suoritaPyynto()
{
// Alustetaan ensin Pyynto-muuttuja kutsumalla edellä toteutettua funktiota
alustaPyynto();
// Määritellään funktio, joka suoritetaan, kun vastaus palvelimelta on saapunut
Pyynto.onreadystatechange = kasitteleVastaus;
// Käytetään POST-tapaa datan lähettämiseen asynkronisesti
// palvelimelle serveriskripti-nimiselle skriptille:
Pyynto.open("POST", "serveriskripti.php", true);
// Asetetaan HTTP-otsake kertomaan sisällön tyyppi
Pyynto.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
// Lähetetään pyyntö palvelimelle
Pyynto.send("nimi=Arvo");
}
POST-tavassa lähetettävä data annetaan parametriksi send-metodille. Tällöin on myös asetettava HTTP-otsake "Content-Type", joka kertoo serveriskriptille minkälaista tietoa on tulossa.
Kun lähetetään useampia arvoja erotetaan ne toisista ampersandilla (&)
// Lähetetään pyyntö palvelimelle
Pyynto.send("nimi1=Arvo1"&"nimi2=Arvo2");
Sovelluksen toteutus aloitetaan eli kutsutaan suoritaPyynto-funktiota, vaikkapa jollain tapahtumankäsittelijällä. Seuraavalla koodilla sovellus käynnistetään painiketta napsauttamalla.
<input type="button" value="Suorita sovellus" onclick="suoritaPyynto()" />
Kun vastaus on saatu suoritetaan kasitteleVastaus-funktio, joka kutsutaan onreadystatechange-metodilla.
function kasitteleVastaus()
{
// Tarkistetaan, onko pyyntö suoritettu kokonaan
if(Pyynto.readyState == 4)
{
// Tarkistetaan, onko pyynnön suoritus onnistunut
if(Pyynto.status == 200)
{
// Jos kaikki on kunnossa, käsitellään saapunut data
alert(Pyynto.responseText);
}
else
{
alert("Pyynnön suorituksessa on tapahtunut virhe!");
}
}
}
Funktiossa tarkistetaan ensin, onko pyyntö suoritettu kokonaisuudessaan, jolloin readyState-ominaisuuden arvoksi tulee 4. Tämän jälkeen tutkitaan, onko pyynnön suorittaminen onnistunut vai onko tapahtunut virhe. Onnistunut pyynnön suorittaminen asettaa status-ominaisuuden arvoksi 200. Sen sijaan esimerkiksi virhekoodi 404 kertoo, ettei annetusta osoitteesta löytynyt sivua (skriptiä).
Palvelimen lähettämä data saadaan poimittua esille responseText-ominaisuudesta, joka sisältää datan tekstimuotoisena.
Kun data on vastaanotettu, sen jatkokäsittely tapahtuu muiden tekniikoiden kuten JavaScript ja DOM avulla.
Koko esimerkki GET-tavalla:
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<title>Sivun otsikko</title>
<meta http-equiv="content-type"
content="text/html;charset=utf-8" />
<meta http-equiv="Content-Style-Type" content="text/css" />
<script type="text/javascript">//koko esimerkki GET-tavalla
// Esitellään muuttuja XMLHTTPRequest-objektille:
var Pyynto;
// Alustetaan Pyynto-muuttuja
function alustaPyynto()
{
Pyynto = new XMLHttpRequest();
}
// Muodostetaan funkito, jota käytetään haettuun dataan
function kasitteleVastaus()
{
// Tarkistetaan, onko pyyntö suoritettu kokonaan
if(Pyynto.readyState == 4)
{
// Tarkistetaan, onko pyynnön suoritus onnistunut
if(Pyynto.status == 200)
{
// Jos kaikki on kunnossa, käsitellään saapunut data
alert(Pyynto.responseText);
}
else
{
alert("Pyynnön suorituksessa on tapahtunut virhe!");
}
}
}
// Käytetään GET-tapaa datan välittämiseen palvelimelle
function suoritaPyynto()
{
// Alustetaan Pyynto-muuttuja kutsumalla edellä toteutettua funktiota
alustaPyynto();
// Määritellään funktio, joka suoritetaan, kun vastaus palvelimelta on saapunut
Pyynto.onreadystatechange = kasitteleVastaus; // HUOM: funktion nimi ilman sukeita
// Käytetään GET-tapaa datan lähettämiseen asynkronisesti
// palvelimelle serveriskripti.php-nimiselle skriptille
Pyynto.open("GET", "serveriskripti.php?nimi=Arvo", true);
// Lähetetään pyyntö palvelimelle
Pyynto.send(null);
}
</script>
</head>
<body>
Sisältö
</body>
</html>
XML-muotoisen datan käsittely
muokkaaXML-datan käsittely tapahtuu pääosin DOM-mallin metodeja ja ominaisuuksia hyödyntämällä. Kun data lähetetään palvelimelta XML-muotoisena, on palvelimella suoritettavan skriptin alussa kerrottava lähetettävän datan tyyppi. PHP-kielessä tämä tapahtuu seuraavasti.
<?php
// Asetetaan HTTP-otsake, jossa kerrotaan palvelimen selaimelle lähettämän tiedon tyyppi:
header("Content-type: text/xml");
// Tähän varsinainen skripti
?>
Lähetettävän datan on oltava XML-standardin mukaista.
<?xml version="1.0" encoding="utf-8"?>
<henkilot>
<henkilo>
<nimi>Matti</nimi>
<osoite>Paratiisitie 13</osoite>
</henkilo>
<henkilo>
<nimi>Maija</nimi>
<osoite>Parasiitie 14</osoite>
</henkilo>
</henkilot>
XML-datan elementteihin pääsee käsiksi DOM-metodeilla ja -ominaisuuksilla. getElementsByTagName-metodilla voidaan XML-datasta hakea vaikkapa kaikki osoite-elementit taulukkoon. Jokaisella osoite-elementillä lapsinodet, joihin päästään käsiksi childNodes-ominaisuuden avulla. Seuraava esimerkki havainnollistaa asiaa.
var osoitteet = Pyynto.responseXML.getElementsByTagName("osoite");
var osoite = osoitteet[0].childNodes[0].nodeValue;
Kaikki osoite-nimiset elementit haetaan osoitteet-taulukkoon ja sitten osoitteet-taulukosta otetaan ensimmäinen osoite-elementti (osoitteet[0]), ja sen ensimmäinen lapsisolmu (childNodes[0]). Tämän solmun arvo "Paratiisitie 13" löytyy nodeValue-ominaisuudesta.