Comunicació asíncrona amb AJAX¶
Què és AJAX¶
AJAX és un conjunt de tècniques de desenvolupament web que permet crear aplicacions web asíncrones, que poden enviar i fer peticions de dades a un servidor web en segon pla quan la pàgina ja ha acabat de carregar, i rebre'n la resposta i processar-la sense necessitat de recarregar la pàgina.
Això permet fer actualitzacions del contingut d'una pàgina web de manera immediata, permetent millorar l'experiència d'usuari (UX) i aconseguint que les pàgines web es comportin de forma similar a les aplicacions d'escriptori.
Origen¶
El disseny inicial del que s'acabria convertint en AJAX se li deu a l'equip de Microsoft que a finals dels anys 90 treballava desenvolupant l'eina Outlook Web Access, un client de correu via web que formava part de Microsoft Exchange Server 5.0.
Van trobar-se amb la necessitat de poder mostrar el contingut d'un missatge de correu individual sense haver de recarregar la pàgina web sencera. Tot i que des de 1997 exisitien els iframes, necessitaven un sistema més eficient per transferir només dades al front-end JavaScript.
Van crear l'especificació d'un nou objecte del llenguatge JScript, incialment anomenat XMLHTTP i només disponible per Internet Explorer. Posteriorment, al 2006 el W3C l'estandaritzaria com a XMLHttpRequest i l'incorporarien la resta de navegadors com a part oficial del llenguatge JavaScript.
AJAX és l'acrònim de "JavaScript Asíncron i XML":
[ A ] synchronous
[ J ] avaScript
[ A ] nd
[ X ] ML
Tot i que el nom sembla implicar que calgui treballar amb XML per utilitzar AJAX, això no és així, sinó que les sigles s'han conservat tal i com el nom era originalment, ja que en aquell moment (inicis dels anys 2000) l'intercanvi d'informació es feia principalmet en format XML.
Actualment, el mètode més extès consisteix en codificar la informació en format JSON.
JSON¶
És un format d'intercanvi de dades en un format fàcilment llegible per humans.
L'especificació del format la va fer Douglas Crockford l'any 2001.
JSON és l'acònim de "Notació d'Objectes de JavaScript":
[ J ] ava
[ S ] cript
[ O ] bject
[ N ] otation
Originalment es va dissenyar per utilitzar-lo amb JavaScript, però actualment l'utilitzen molts altres llenguatges i tecnologies per intercaviar informació entre aplicacions i amb servidors web.
El format de JSON permet emmagatzemar i transmetre dades en format de parelles clau/valor separades per dos punts (":"):
"nom": "John"
Les dades poden amés estar esctructurades com a arrays, objectes o combinacions d'aquests:
{
"nom": "John",
"cognom": "Smith",
"edat": 20,
"telefons": [
{
"tipus": "fix",
"numero": "123456789"
},
{
"tipus": "mòbil",
"numero": "987654321"
}
]
}
A diferència d'un objecte nadiu de JavaScipt, la sintaxi de JSON requereix que el nom de les claus estiguin entre cometes.
També cal tancar entre cometes les cadenes de text (que es codifiquen en UTF-8), però no és necessari fer-ho pels valors numèrics.
{
"nom": "John",
"cognom": "Smith",
"edat": 20,
"telefons": [
{
"tipus": "fix",
"numero": "123456789"
},
{
"tipus": "mòbil",
"numero": "987654321"
}
]
}
{
nom: "John",
cognom: "Smith",
edat: 20,
telefons: [
{
tipus: "fix",
numero: "123456789"
},
{
tipus: "mòbil",
numero: "987654321"
}
]
}
Ús d'AJAX¶
Podem utilitzar AJAX de diverses formes:
-
Utilitzant l'objecte XMLHttpRequest (abreujat com a XHR)
És el mètode original, i és compatible amb tots els navegadors que tenen suport per AJAX.
Consisteix en crear un objecte XMLHttpRequest, assignar-li una funció de retorn, i processar allà la resposta a la petició AJAX. -
A través d'una biblioteca externa (per exemple, AXIOS)
Existeixen moltes biblioteques de JavaScript (jQuery, Prototype, MooTools) que incorporen funcions per realitzar de manera senzilla peticions AJAX.
La sintaxi sol ser bastant simplificada respecte a utilitzar l'objecte XMLHttpRequest i processar el resultat. Per contra, requereixen carregar sempre la biblioteca externa per utilitzar-les.
La biblioteca més popular i completa per treballar amb AJAX és AXIOS. -
A través de l'API fetch
Per simplificar les peticions AJAX i acostar-les més a la sintaxi més senzilla que proporcionen les biblioteques externes, l'any 2015 es va introduir a JavaScript l'API fetch, com a substitut modern de XMLHttpRequest.
Està basada en promeses i és suportada per tots els navegadors actuals, per tant es pot utilitzar sense restriccions.
La seva sintaxi és similar a la d'AXIOS, tot i que aquesta última és més completa.
Comparatives d'AXIOS vs fetch API
Axios vs. fetch(): Which is best for making HTTP requests?
When do you need axios?
Política CORS¶
CORS (Cross-Origin Resource Sharing, Compartició de Recursos entre Orígens Creuats) és una política de seguretat per les peticions HTTP asíncrones (XHR) entre un navegador i un servidor que es trobin en dominis diferents. Afecta només les peticions AJAX, ja siguin fetes a través d'XMLHttpRequest, AXIOS o altres biblioteques, o bé fetch.
Com a protecció, CORS impedeix per defecte l'accés asíncron als recursos situats en dominis diferents al de la pàgina actual. Té com a finalitat dificultar la posibilitat d'abusar d'APIs externes o modificar recursos aliens.
Si volem permetre permanentment les peticions entre orígens creuats, la forma més senzilla és fer que el servidor web retorni la capçalera Access-Control-Allow-Origin a les pàgines de resposta que genera, ja sigui individualment a cada pàgina, a la configuració del servidor web o al fitxer htaccess.
Si només ens interessa no rebre errors de CORS mentre estem desenvolupant, una opció temporal pot ser instal·lar l'extensió Allow CORS, disponible tant per Chrome com Firefox. Aquesta extensió permet deshabilitar la política CORS del nostre navegador mentre estem en procés de desenvolupament, i per exemple treballem amb una API hostatjada en un servidor diferent del que té el codi de client.
Exemples d'ús d'AJAX¶
Els codis de prova que es mostren a continuació utilitzen un conjunt de dades en format SQL generat amb la web Mockaroo.com, que podem utilitzar per generar grans quantitats de dades fictícies per fer proves amb les nostres APIs.
Codi PHP que retorna les dades del backend
<?php
// Connexió a la base de dades
$mysqli = new mysqli($host, $user, $password, $db);
// Obtenim el filtre de dades que ens pot arribar per GET
$filtre = isset( $_GET["filtre"] ) ? "WHERE (first_name LIKE '%".$_GET["filtre"]."%') OR (last_name LIKE '%".$_GET["filtre"]."%') " : "";
// Preparem la consulta
$consulta = $mysqli->query( "SELECT * FROM usuaris " . $filtre . "ORDER BY last_name" );
// Array on deixarem les dades que retorni la consulta
$resultat = array();
// Recorrem els resultats de la consulta
while ( $registre = mysqli_fetch_assoc( $consulta ) )
{
// Afegim cada resultat a l'array que retornarem
array_push($resultat, $registre);
}
// Retornem l'array de resultats en format JSON
echo json_encode($resultat);
Amb XMLHttpRequest¶
Cal realitzar múltiples passos per fer la petició amb aquest mètode:
-
Crear un objecte XMLHttpRequest
var xmlhttp = new XMLHttpRequest()
-
Assignar-li l'esdeveniment readystatechange
xmlhttp.onreadystatechange = function () { ... }
-
Inicialitzar la petició amb el mètode open, indicant el mètode i la URL
xmlhttp.open( mètode, URL )
-
Enviar la petició al servidor amb send
xmlhttp.send()
-
Esperar la resposta assíncrona, que passarà per diversos estats de XMLHttpRequest fins completar-se en un estat HTML. Cada cop que hi hagi un canvi, el codi entrarà a la funció assignada a l'esdeveniment
readystatechange
Possibles valors de readyState
Valor | Descripció |
---|---|
0 | S'ha creat l'objecte, però encara no s'ha definit la petició |
1 | S'ha executat el mètode open() per preparar la petició |
2 | S'ha executat el mètode send() , la petició s'ha enviat al servidor |
3 | S'està descarregant les dades, però encara no s'han rebut totes |
4 | Procés finalitzat, ja no rebrem cap més dada del client. Aquest és el valor que esperarem al nostre codi IMPORTANT: en aquest punt pot ser que haguem rebut les dades esperades o bé un missatge d'error del servidor. Només sabem segur que la petició s'ha acabat de processar. |
Valors habituals de status
Valor | Codi | Descripció |
---|---|---|
200 | OK | La petició ha finalitzat correctament i sense errors Aquest és el valor que esperarem al nostre codi |
400 | Bad request | Petició incorrecta, normalment degut a algun error de sintaxi a la URL |
401 | Unauthorized | Cal autenticació per accedir al contingut, però no l'hem proporcionat o bé les credencials no són correctes |
403 | Forbidden | No tenim drets d'accés al contingut sol·licitat, però no és un problema d'autenticació sinó de permisos (si no seria un error 401) |
404 | Not found | El servidor no pot trobar el contingut sol·licitat, ja sigui perquè no es troba un recurs (p.ex. un fitxer) o perquè l'endpoint sol·licitat no està definit |
500 | Internal Server Error | Error genèric que el servidor no pot processar, pot ser indici d'algun error al codi del back-end |
- Processar les dades rebudes amb responseText, si són dades JSON les convertirem a un objecte de JavaScript amb
JSON.parse()
per poder treballar-hi
resposta = JSON.parse( xmlhttp.responseText )
Codi complet de la petició
// Creem un objecte de petició d'intercanvi de dades
var xmlhttp = new XMLHttpRequest()
// Associem una funció per comprovar quan la petició ha canviat d'estat
xmlhttp.onreadystatechange = function () {
// Si la petició s'ha completat correctament
// rebrem un codi 200 i serem a l'estat 4
if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
// Tenim les dades rebudes del servidor dins de xmlhttp.responseText
// Com que sabem que estan en format JSON, convertim la resposta en
// un objecte que guardem a la variable "resposta"
resposta = JSON.parse(xmlhttp.responseText)
// Cridem la funció que processarà les dades retornades
processarDades(resposta)
}
}
// Indiquem el mètode (GET) i la URL del servidor que ens retornarà les dades
xmlhttp.open("GET", "consulta.php")
// Llancem la petició assíncrona al servidor
xmlhttp.send()
Amb Axios¶
Axios simplifica el codi de les peticions AJAX.
Cada mètode de petició HTTP (get
, post
, put
, delete
, etc.) té un mètode d'AXIOS associat.
Cal tenir en compte que perquè funcionin cal carregar primer el codi del client Axios.
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
axios.get("consulta")
.then(function (resposta) {
processarDades(resposta.data);
});
Podem fer el mateix utilitzant funcions fletxa:
axios.get("consulta.php?filtre=" + dades)
.then(resposta => {
processarDades(resposta.data);
});
Web d'Axios
Axios a GitHub
Documentació de "dog API" (per l'exemple anterior)
Amb fetch¶
fetch("consulta.php", {
method: "GET" // Mètode per defecte
})
.then(function (resposta) {
resposta.json()
.then(function (dades) {
processarDades(dades);
});
});