Che cos'è AJAX?

Questo articolo cerca di dare una risposta alle seguenti domande: che cos'è AJAX? Cosa vuol dire scrivere applicazioni AJAX? Perchè si dovrebbe conoscere AJAX? Cosa c'entra Java in tutto questo? Viene presentato un semplice esempio per mettere in pratica tutto quello che viene descritto.

AJAX non è l'ennesima architettura per il mondo web; in realtà è l'unione di molte tecnologie Open Source già esistenti. Infatti, AJAX è un termine coniato da Jesse James Garrett nel 2005 e sta per Asynchronous Javascript And XML e raggruppa in una sola parola la tecnica per realizzare applicazioni web più dinamiche, più user-friendly e più facilmente fruibili dall'utente finale. Vediamo il dettaglio di ciascun termine:

  • Asynchronous: è il tipo di colloquio tra client e server.
  • Javascript: è il linguaggio che viene utilizzato dal browser sul client all'interno di una pagina web per poter richiamare il server e valutare la risposta.
  • XML: i dati che transitano tra Client e Server possono essere tracciati XML il cui contenuto è composto solo dai dati necessari alla pagina web e tramite gli oggetti Javascript DOM è possibile leggerli e manipolarli.

Oltre a questo, ovviamente, c'è sempre HTML e CSS per disegnare le pagine web e DHTML per rendere dinamico il contenuto delle medesime. AJAX è un nuovo modo per sviluppare le applicazioni WEB. Alcuni esempi sono già presenti su internet come ad esempio:

  • Writely (http://www.writely.com)
  • Google Maps (http://maps.google.com/)
  • Google Readers
  • Gmail (http://mail.google.com/mail/)
  • Google Suggest (http://www.google.com/webhp?complete=1)
  • Flickr (http://www.flickr.com/)

Applicazioni web tradizionali

Figura 1 - Schema del modello tradizionale di applicazioni web
Figura 1 - Schema del modello tradizionale di applicazioni web

Come rappresentato in Figura 1, le applicazioni web solite funzionano in questo modo: l'utente effettua una REQUEST verso il server a fronte di una specifica azione (clic su un bottone, su un link, su un'immagine, ecc.); il server riceve i dati di una FORM via GET o POST, effettua una elaborazione dei dati e prepara la RESPONSE spedendo al client una nuova pagina web che andrà a sostituire (o a ricaricare) la pagina precedente presente sul browser dell'utente.

La caratteristica di questa modalità di colloquio è che c'è sempre qualcuno che deve aspettare: il server aspetta sino a quando un client non effettua una GET/POST e un client aspetta sino a quando il server non ha concluso l'elaborazione e preparato la pagina HTML di output. Per ridurre questi tempi di attesa e rendere il client ed il server più interconnessi tra loro, è stato studiato un nuovo modo di scrivere le applicazioni web.

Applicazioni AJAX

Figura 3 - Schema del modello AJAX
Figura 3 - Schema del modello AJAX

Come mostrato in figura 3, le applicazioni web utilizzano AJAX nel modo seguente: un'applicazione AJAX elimina questo approccio di inizio e fine comunicazione (REQUEST e RESPONSE) utilizzando invece un motore AJAX che viene richiamato nella pagina web e si preoccupa di dialogare con il server in modo asincrono (o sincrono).

Figura 4 - Dettaglio del motore AJAX
Figura 4 - Dettaglio del motore AJAX

Come illustrato in figura 4, il motore AJAX ha il compito di comunicare in modo asincrono con il server in base a particolari eventi (scrittura in un campo TEXT, selezione di un elemento di una COMBO, ecc.) e deve richiamare le opportune funzioni Javascript che ridisegnano dinamicamente le pagine web. In questo modo, l'utente non dovrà più attendere che la pagina venga ricaricata ma semplicemente la vedrà cambiare davanti ai sui occhi contestualmente ai dati che sta immettendo nella FORM.

Fino ad ora, nulla è stato detto sulla parte server. Infatti, AJAX è specifico per il Presentation Layer e il server può seguire una qualsiasi tecnologia disponibile: J2EE con linguaggio Java o LAMP con linguaggio PHP oppure .Net con C#. È il motore AJAX che dovrà dialogare con un protocollo standard (XML o SOAP) oppure proprietario (testo, CSV, ecc.) con il server. In questo articolo, l'esempio che in seguito verrà illustrato è focalizzato sulla tecnologia J2EE con il linguaggio Java e in particolare con JDK 1.4.2_11 e Jakarta Tomcat 5.0.27 come Web container.

Esempio pratico: validazione codice fiscale

Vediamo adesso l'anatomia del modello AJAX calato su un esempio pratico: la verifica della correttezza di un codice fiscale digitato da un utente.

Figura 5 - Passi di una iterazione AJAX
Figura 5 - Passi di una iterazione AJAX

I passi che vengono eseguiti in un'iterazione AJAX (come illustrato in figura 5) sono i seguenti. Qui di seguito verranno analizzati in dettaglio i vari punti.

Passo 1: Intercettazione dell'evento

Nella pagina web, il campo codicefiscale intercetta l'evento onkeyup: ad ogni pressione di tasto viene richiamata la funzione javascript validate(). L'evento è di solo esempio: in una mappa più complessa con molti campi di input sicuramente è meglio gestire gli eventi onchange oppure onblur.

Passo 2: Funzione validate()

Il corpo della funzione validate è il cuore del motore AJAX. Per prima cosa, legge i parametri della FORM:

// Leggo il parametro della FORM
var cf = document.getElementById("codicefiscale");

e definisce alcune variabili di appoggio:

// URL del server da richiamare per la validazione
var url = "codiceFiscaleValidationServlet";
// Funzione che verra' richiamata al ritorno
var callback = validateCallback;

In seguito, viene istanziato l'oggetto XMLHttpRequest. Questo si deve fare in modo diverso in base al browser utilizzato: con Mozilla, Firefox e Safari, l'oggetto XMLHttpRequest è definito nel linguaggio javascript, mentre con Internet Explorer deve essere caricato un opportuno ActiveX (diverso inoltre tra versioni precedenti alla 5.5 o superiore).

// Istanza dell'oggetto XMLHttpRequest
var xmlhttp = false;
// Se Mozilla, Firefox, Opera, Safari
if (window.XMLHttpRequest) {
  xmlhttp = new XMLHttpRequest();
// Se IE
} else if (window.ActiveXObject) {
  try {
    // Versione 5.5 o inferiore
    xmlhttp = new ActiveXObject("Msxml2.XMLHTTP");
  } catch (e) {
    try {
      // Versione 5.5 o superiore
      xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
    } catch (e) {
    }
  }
}
// Se oggetto non istanziato: errore
if (!xmlhttp) {
  alert("ERRORE: AJAX non supportato da questo browser!");
  return false;
}

Viene impostato il modo di colloquio con il server: verrà invocato l'url specificato tramite una POST in modo asincrono (terzo parametro impostato a true).

// Apro la connessione verso il server in modo asincrono
xmlhttp.open('POST', url, true);

Il colloquio può anche essere fatto via HEAD o via GET. Poi si definisce la funzione javascript di ritorno che verrà richiamata alla fine dell'esecuzione della parte server.

// Il ritorno viene intercettato da questa funzione
xmlhttp.onreadystatechange = function () {
  // 4 significa completato
  if (xmlhttp.readyState == 4) {
    // Codice di ritorno del server: 200 vuol dire OK
    if (xmlhttp.status == 200) {
      // Leggo il ritorno in formato XML
      if (callback) {
        callback(xmlhttp.responseXML);
      }
    } else if (xmlhttp.status == 404) {
      alert("ERRORE: L'url richiesto non esiste!");
    } else {
      alert("ERRORE: Codice di ritorno=" + xmlhttp.status);
    }
  }
}

L'attributo readyState dell'oggetto XmlHttpRequest contiene lo stato di esecuzione della chiamata fatta al server; i valori possibili sono i seguenti:

  • 0 = non inizializzato
  • 1 = in caricamento
  • 2 = caricato
  • 3 = interattivo
  • 4 = completato

L'attributo status dell'oggetto XmlHttpRequest contiene lo stato di ritorno del protocollo HTTP; alcuni valori sono:

  • 200 = richiesta valida
  • 404 = url inesistente

L'attributo responseXML dell'oggetto XmlHttpRequest contiene il tracciato XML DOM compatibile, altrimenti l'attributo responseText contiene la risposta in formato testo.

Viene dichiarato il tipo di Header del messaggio:

// Codifica dei campi secondo il MIME type corretto
xmlhttp.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');

e infine viene richiamato il server, facendo attenzione a convertire i caratteri dei parametri nella codifica valida per internet:

// Invio i parametri
xmlhttp.send('codicefiscale=' + encodeURIComponent(cf.value));

Se il colloquio con il server non viene fatto via POST ma via GET allora, si deve preparare un url con tutti i parametri concatenati e poi richiamare il metodo send o con null o con stringa vuota, ossia:

// URL del server da richiamare per la validazione
var url = "codiceFiscaleValidationServlet?codiceficale=" + encodeURIComponent(cf.value);
// Apro la connessione verso il server in modo asincrono
xmlhttp.open('GET', url, true);
// Invio i parametri
xmlhttp.send(null);

Si deve anche notare che l'oggetto XmlHttpRequest viene eseguito all'interno del browser e pertanto adotta le stesse policy di sicurezza del linguaggio javascript.

Passo 3: Il server legge i parametri

Il server legge i parametri ricevuti dal client:

String codiceFiscaleParam = request.getParameter("codicefiscale");

Prepara l'output in formato XML:

request.setCharacterEncoding("UTF-8");
response.setContentType("text/xml");

Inoltre, si faccia particolare attenzione anche a gestire in modo corretto la cache del browser in modo che non vengano salvate le informazioni sul client.

response.setHeader("Cache-Control", "no-cache");

Infine viene verificata la correttezza del codice fiscale:

CodiceFiscale cf = new CodiceFiscale();
boolean retValue = false;
try {
  retValue = cf.verifica(codiceFiscaleParam);
} catch (CodiceFiscaleException e) {
}
if (retValue) {
  response.getWriter().write("<valid>true</valid>");
} else {
  response.getWriter().write("<valid>false</valid>");
}

La servlet restituisce un messaggio XML contenente true nel caso in cui sia valido, altrimenti false.

Passo 4: Callback e aggiornamento della pagina

Al ritorno sul browser, viene richiamata la funzione javascript validateCallback:

var msg = responseXML.getElementsByTagName("valid")[0].firstChild.nodeValue;

e viene letto il messaggio di ritorno dal tracciato XML.

A questo punto, viene aggiornata la pagina HTML:

var mdiv = document.getElementById("message");
if (msg == "false") {
  // Codice Fiscale non valido
  mdiv.className = "bp_invalid";
  mdiv.innerHTML = "Codice Fiscale non valido!";
  var submitBtn = document.getElementById("submit_btn");
  submitBtn.disabled = true;
} else {
  // Valido
  mdiv.className = "bp_valid";
  mdiv.innerHTML = "Codice Fiscale corretto";
  var submitBtn = document.getElementById("submit_btn");
  submitBtn.disabled = false;
}
Figura 6 - Codice fiscale errato
Figura 6 - Codice fiscale errato
Figura 7 - Codice fiscale corretto
Figura 7 - Codice fiscale corretto

Vantaggi e svantaggi di AJAX

L'utilizzo di AJAX, così come ogni altra tecnologia, presenta una serie di vantaggi e di svantaggi.

Vantaggi:

  • Maggiore interattività e user-friendliness dell'applicazione
  • Riduzione del traffico di rete (vengono trasferiti solo i dati necessari)
  • Migliore esperienza utente (nessun reload completo della pagina)
  • Possibilità di creare applicazioni web simili a quelle desktop

Svantaggi:

  • Maggiore complessità nello sviluppo
  • Problemi di compatibilità tra browser
  • Difficoltà nel debugging
  • Problemi con l'utilizzo del tasto "Indietro" del browser
  • Necessità di gestire correttamente il Javascript disabilitato

Descrizione dell'esempio

Qui di seguito viene data una breve descrizione del contenuto del file zippato di esempio ajax_codicefiscale.zip.

  • ./build.xml: Script di ANT per compilare le classi, generare il JAR, il WAR e fare il deploy su Tomcat.
  • ./classes: Directory che contiene i compilati.
  • ./dd/war/WEB-INF/web.xml: Descrittore del Web Container.
  • ./lib/ajaxcodicefiscale.jar: Pacchetto delle classi compilate.
  • ./src/java: Sorgenti java.
  • ./src/web: Pagine web. In particolare, index.jsp contiene tutta la parte relativa ad AJAX discusse in questo articolo.
  • ./tmp/ajaxcodicefiscale.war: Il pacchetto WAR per il deploy.

Per chi vuole subito vedere l'esempio, è sufficiente copiare il file ajaxcodicefiscale.war all'interno della cartella webapps di Jakarta-Tomcat, lanciare Tomcat e aprire il link http://localhost:8080/ajaxcodicefiscale/

Per chi, invece, vuole compilare i sorgenti e rigenerare il pacchetto WAR, può utilizzare i seguenti comandi di ANT previsti nello script:

# ant all
# Per compilare e generare il file WAR

# ant tomcat.deploy
# Per effettuare il deploy

# ant tomcat.run
# Per lanciare Jakarta-Tomcat

Conclusioni

In questo articolo sono stati affrontati i concetti basilari di AJAX necessari per comprendere al meglio questo nuovo approccio.

Bibliografia

1. Nicholas C. Zakas, Jeremy McPeak, Joe Fawcett – "Professional Ajax", Wrox, 02/2006 2. Jesse James Garrett – "Ajax: A New Approach to Web Applications" - http://www.adaptivepath.com/publications/essays/archives/000385.php 3. Brett McLaughlin – "Mastering Ajax, Part 1: Introduction to Ajax" - http://www-128.ibm.com/developerworks/java/library/wa-ajaxintro1.html 4. Brett McLaughlin – "Mastering Ajax, Part 2: Make asynchronous requests with JavaScript and Ajax" - http://www-128.ibm.com/developerworks/java/library/wa-ajaxintro2/index.html 5. Brett McLaughlin – "Mastering Ajax, Part 3: Advanced requests and responses in Ajax" - http://www-128.ibm.com/developerworks/java/library/wa-ajaxintro3/index.html 6. Brett McLaughlin – "Mastering Ajax, Part 4: Exploiting DOM for Web response" - http://www-128.ibm.com/developerworks/java/library/wa-ajaxintro4/index.html 7. "AJAX Tutorial" - http://www.w3schools.com/ajax/default.asp 8. Apple, "Dynamic HTML and XML: The XMLHttpRequest Object" - http://developer.apple.com/internet/webcontent/xmlhttpreq.html