Sommario
< Home
Stampa

AJAX

Introduzione ad AJAX

AJAX (Asynchronous Javascript and XML1) è il nome con cui viene chiamata la funzione che usa Javascript nel browser per comunicare con servizi Internet, ed aggiornare quindi i contenuti visualizzati senza ricaricare la pagina.

Grazie ad AJAX la pagina web diventa una applicazione connessa ad Internet. Il principio di funzionamento è questo:

  • il browser scarica HTML/CSS e lo script JS;
  • lo script JS scarica da uno o più server remoti i dati necessari all’utilizzo della pagina;
  • l’utente interagisce con la pagina;
  • la pagina si aggiorna dinamicamente inviando e ricevendo dati col server remoto.

L’applicazione sul server che si occupa di inviare/ricevere dati è chiamato Web Service.

Un esempio di applicazione di questo tipo è Gmail: le mail vengono dinamicamente scaricate dallo script di pagina, e l’utente può leggerle, rispondere, cancellare, spostare le mail. La pagina web diventa quindi non solo un contenuto dinamico ma una vera e propria applicazione.

Grazie ad AJAX, Javascript è in grado di sostituire la maggior parte delle applicazioni desktop e grazie a questa tecnologia vengono abbattute le barriere che esistono tra un pc, un tablet ed uno smartphone in termini di potenza di calcolo ed operazioni possibili.

Protocollo HTTP

Alla base di AJAX c’è il protocollo HTTP.

Il protocollo HTTP è un protocollo di comunicazione a livello applicazione dello stack TCP/IP, che sta alla base di tutta la tecnologia del Web.

Questo protocollo prevede una comunicazione tra un client (cioè il browser) ed un server (il Web Service).

Il protocollo prevede che il client generi una richiesta HTTP (Http Request) e il server risponda con una risposta HTTP (Http Response). 

Esso ha le seguenti caratteristiche distintive:

  • Request e Response sono in formato testo, ma possono contenere dati binari codificati nel corpo della richiesta;
  • è una connessione punto-punto: in altre parole solo due sono i nodi (host) coinvolti, il client ed il server;
  • il client ha un ruolo attivo: solo il client può originare la richiesta verso il server, e ne attende la risposta.
  • Il server è invece in attesa passiva di richieste dal client. Il Web service resta in attesa di richieste e ed elabora le risposte. Non è possibile inviare dati al client senza una richiesta.
  • http è senza sessione. Ogni richiesta-risposta è sempre indipendente dalle altre. Non c’è modo, col solo protocollo http, sapere se la richiesta è parte di una sequenza oppure no.
  • è opzionalmente previsto uno strato di sicurezza tramite protocollo TLS (che esegue la criptazione dei dati): combinati insieme danno origine al protocollo https.

HTTP Request

Il protcollo prevede una struttura predefinita per la richiesta.

La Request comprende 3 parti:

– una intestazione iniziale, che contiene la URL il protocollo e il metodo della chiamata. Il metodo indica il tipo di rhciesta. Le più comuni sono GET (ricezione dati), POST (invio di nuovi dati), PUT (modifica dei dati), DELETE (cancellazione dati), ma ne sono previsti anche altri.

– l’header della chiamata: contiene delle coppie chiave-valore che contengono informazioni di servizio della chiamata (es. dati autenticazione, formato dei dati della richiesta, cookies, ecc.).

– il body della chiamata: è un campo utilizzato per alcuni metodi (POST-PUT) e contiene i dati inviati al server.

La URL

La URL (Uniform Resource Locator) rappresenta in una stringa di testo che server per identificare in modo univoco le risorse richieste.

La URL identifica il protocollo (http, https), il server (cioè il nome della macchina, comprensiva di dominio e sottodominio), la porta (non obbligatorio indicarla se 80), il path della risorsa (identificata come un filesystem virtuale, non è obbligatorio e dipende dalla configurazione del server) ed eventuali richieste aggiuntive opzionali sulla risorsa stessa (detta query string, non obbligatoria nemmeno questa). 

Qui la struttura della stringa: 

http[s]://[thirdleveldomain.]secondlevel.firstleveldomain[:port]/[path/to/resource][?ke1=value1][&key2=value2]...

Le parti tra parentesi quadre sono opzionali

Qui qualche esempio di url con tutti gli elementi

http://www.myserver.org/path/to/resource.html?p1=1&p2=ciao
https://www.google.com
https://cipiaceinfo.it/docs/programmazione/javascript/ajax

HTTP Response

Una volta che il server elabora la request, prepara la Response, che contiene 3 parti:

– l’intestazione: essa indica con un codice di status l’esito della risposta (alcuni codici sono 200 OK, 401 non autorizzato, 404 non trovato, 500 errore, ecc.);

– l’header della risposta: contiene delle coppie chiave-valore che contengono informazioni di servizio (es., indica il formato dei dati inviati, regole di sicurezza, codici di autenticazione, cookies, ecc.) in modo analogo a quanto avviene con la richiesta

– il body della risposta con i contenuti inviati.

Fetch

Con JS viene utilizzata la funzione fetch, parte dell’API del BOM, che consente di definire la struttura della richiesta e di ricevere la risposta.

La chiamata HTTP richiede un certo tempo: la richiesta al server, l’elaborazione lato server, la ricezione della risposta. Tutto questo potrebbe tenere fermo il programma Javascript, bloccando quindi la pagina web. Per questa ragione si usa la programmazione asincrona: si invia la request e si predispone una funzione da eseguire una volta ricevuta la risposta (detta callback). La chiamata effettiva sarà svolta da un thread secondario, che aggiungerà la callback alla coda di esecuzione una volta arrivata la risposta. La callback sarà quindi eseguita quando Javascript tornerà pronto.

La funzione che esegue tutto questo si chiama fetch (ed è compresa nell’oggetto Window, quindi nel BOM). Qui graficamente viene mostrato lo schema generale di funzionamento:

Quel che deve fare il programmatore è richiamare fetch con i parametri della richiesta (url, e quando necessari anche header e body). Nella sua struttura più semplice, ovvero una richiesta di dati al server, è necessaria solo la URL e si usa il metodo GET, che come detto serve nella maggior parte dei casi per ricevere dati.

La fetch viene eseguita in modalità asincrona ed è una promise.

GET

Qui un esempio di chiamata fetch:

fetch("https://dummyjson.com/c/d3f5-e907-4ca1-afa6")
       .then(response => response.json())
       .then(data => console.log(data));

La console stamperà questo:

[
  {
    "firstName": "Mario",
    "lastName": "Rossi"
  },
  {
    "firstName": "Marta",
    "lastName": "Bianchi"
  }
]

Analizziamo questo codice.

1) La fetch riceve come argomento la sola URL, la chiamata GET è di default. La fetch genera un oggetto chiamato promise. Questo oggetto prevede un metodo then() che riceve come argomento la callback da eseguire.

2) A questo punto parte il thread secondario che effettua la richiesta, ed attende la risposta, senza bloccare lo script Javascript.

3) Appena ricevuta la risposta il thread secondario aggiunge alla coda di esecuzione la callback indicata nella then().

4) La risposta come abbiamo visto sopra non è composta solo dai dati ma anche da altre informazioni. I dati contenuti nel body della risposta vanno convertiti, in questo caso in formato JSON. Anche questa operazione è asincrona[2], e quindi è necessaria una seconda funzione response.json() che genera una nuova promise. Per questo c’è un secondo “then”, che semplicemente indica la callback da eseguire con i dati ormai ricevuti.[3]

POST

La chiamata POST serve per inviare una richiesta HTTP in cui vengono inviati dei dati al server.

Questo può essere necessario per due ragioni:

– quando il client vuole richiedere informazioni ma le risorse di cui ha bisogno non possono essere inserite nella URL (perché non è possibile inserirle nella URL per ragioni di spazio o riservatezza o anche semplice uniformità).

– quando il client vuole inviare dei dati al server.

La struttura di una chiamata post sarà con la seguente sintassi:

fetch(url, {
   method: "POST",
   headers: {
   	"key": "value",
        ...
   },
   body: content // deve essere una stringa
})
	.then(response => response.json())
	.then(data => ... istruzioni da eseguire);

Riassunto

Fetch è la funzione che permette di comunicare tra l’applicazione Javascript e i servizi su Internet che forniscono e ricevono dati. La richiesta prevede una URL, un metodo, degli headers e un body. In base al metodo alcuni parametri sono obbligatori, altri sono facoltativi o vietati:

  • Con GET si deve inviare la URL, opzionalmente anche gli headers, ma il body non è consentito. Si usa in generale per richiedere una risorsa identificata dalla URL.
  • Con POST invece si inviano la URL, opzionalmente gli headers, ma è previsto l’invio anche del body. Si usa in generale quando dall’applicazione si vogliono inviare dei dati, ad esempio inseriti dall’utente. Non bisogna fare confusione però: la POST si può utilizzare anche quando si richiede una risorsa, ma siccome la richiesta può essere basata su una struttura dati complessa, allora è comunque necessario inviare dei dati.

Gli headers sono delle coppie nome-valore che servono per mandare al server un insieme di informazioni ad esempio sul formato dati e sulla sicurezza. Gli headers sono fondamentali anche per gestire, in molti casi, anche la sicurezza, per esempio inviando un codice di sicurezza per autenticare il client.

Il body della richiesta contiene i dati da inviare al server. In queste lezioni useremo solo il formato JSON sia per i dati inviati che per quelli ricevuti, ma si ricorda che sul web sono presenti molti altri formati, come ad esempio XML.

La fetch è una funzione asincrona, che crea un oggetto promise, che offre un metodo then(). A questo metodo bisogna passare una prima callback che trasforma la risposta in un oggetto Javascript e che è a sua volta una promise a cui colleghiamo una ultima callback in cui i dati sono pronti ed usabili per i nostri scopi.


[1] Asyncronous Javascript and XML (inizialmente si usava solo con il formato XML).

[2] la conversione è asincrona perché può richiedere un tempo significativo che potrebbe bloccare la richiesta.

[3] questo doppio passaggio della fetch potrebbe essere gestito con una sola promise. Nelle prossime lezioni scriveremo un metodo per gestire tutto con una sola promise.

  1. Si chiama così perché il formato di interscambio dati era, inizialmente, XML. Oggi il formato prevalente è JSON. ↩︎