XMLHttpRequest
Apprenez à utiliser XMLHttpRequest (XHR) en JavaScript : méthodes open et send, readyState, événements load/error/timeout, parsing JSON, POST et abort.
JavaScript est un langage de programmation essentiel pour le développement web, permettant des expériences utilisateur dynamiques et interactives. L'une des fonctionnalités clés de JavaScript est sa capacité à communiquer avec des serveurs, récupérer des données et mettre à jour des pages web de manière asynchrone. Cela est principalement réalisé grâce à l'utilisation de XMLHttpRequest (XHR). Cet article propose une exploration approfondie de XMLHttpRequest, incluant ses méthodes, ses propriétés et ses applications pratiques, avec de nombreux exemples de code pour faciliter l'apprentissage.
XMLHttpRequest fonctionne avec des fonctions de rappel (callbacks). Pour du nouveau code, vous vous tournerez généralement vers l'API Fetch à la place, qui est basée sur les promesses et s'utilise proprement avec async/await. XHR vaut toujours la peine d'être compris : vous le rencontrerez dans des bases de code plus anciennes, et il reste la seule API native qui rapporte la progression des uploads avec une granularité fine.
Cette page couvre ce qu'est un objet XHR, comment configurer et envoyer une requête avec open et send, comment lire la réponse via readyState et les événements load/error/timeout, comment parser du JSON, comment envoyer des données en POST, comment annuler une requête et comment XHR se compare à fetch.
Comprendre XMLHttpRequest
XMLHttpRequest (XHR) est un objet natif du navigateur qui permet à JavaScript d'envoyer une requête HTTP ou HTTPS à un serveur et de recevoir la réponse sans recharger la page. Le « XML » dans le nom est historique : XHR peut transférer n'importe quel format texte ou binaire, et JSON est de loin le plus courant aujourd'hui. Cette capacité à communiquer avec un serveur en arrière-plan est le fondement de ce qu'on appelait autrefois AJAX (Asynchronous JavaScript and XML).
Le cycle de vie d'une requête est toujours le même : créer l'objet, l'ouvrir (configurer la méthode et l'URL), attacher des gestionnaires d'événements pour réagir au résultat, puis l'envoyer.
Créer un objet XMLHttpRequest
Commencez par créer une instance :
const xhr = new XMLHttpRequest();Une seule instance XMLHttpRequest gère une seule requête. Pour effectuer une deuxième requête, créez un nouvel objet.
Effectuer une requête HTTP
Une fois l'objet créé, configurez-le avec open, puis envoyez-le avec send.
La méthode open
open initialise une requête mais ne l'envoie pas encore. Elle prend plusieurs paramètres :
xhr.open(method, url, async, user, password);method: La méthode HTTP à utiliser, par exemple'GET'ou'POST'.url: L'URL vers laquelle la requête est envoyée.async: Un boolean indiquant si la requête est asynchrone. Par défauttrue, et vous devriez presque toujours le laisser ainsi (voir l'avertissement ci-dessous).user: Nom d'utilisateur optionnel pour l'authentification HTTP.password: Mot de passe optionnel pour l'authentification HTTP.
Exemple :
xhr.open('GET', 'https://jsonplaceholder.typicode.com/posts/1', true);Les requêtes synchrones (xhr.open(method, url, false)) bloquent la page jusqu'à l'arrivée de la réponse et sont dépréciées sur le thread principal. Gardez toujours async à true.
La méthode send
send envoie la requête au serveur. Tout gestionnaire d'événement doit être attaché avant de l'appeler. Pour une requête GET, appelez-la sans argument. Pour un POST, passez le corps de la requête en argument.
Exemple d'une requête GET :
xhr.send();Exemple d'une requête POST avec des données encodées en formulaire :
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
xhr.send('param1=value1¶m2=value2');La méthode setRequestHeader ajoute un en-tête HTTP à la requête sortante, et doit être appelée après open mais avant send.
Gérer les réponses du serveur
Pour gérer les réponses du serveur, différents écouteurs d'événements peuvent être utilisés.
L'événement onreadystatechange
L'événement onreadystatechange se déclenche chaque fois que la propriété readyState change. La propriété readyState contient le statut du XMLHttpRequest.
0: UNSENT1: OPENED2: HEADERS_RECEIVED3: LOADING4: DONE
Une requête est terminée et réussie uniquement lorsque readyState vaut 4 (DONE) et que le status HTTP est dans la plage de succès (généralement 200). Ne vérifier que readyState === 4 est une erreur courante, car le serveur peut avoir répondu avec 404 ou 500.
Exemple :
Bien que onreadystatechange fonctionne, le code moderne préfère généralement onload et onerror pour une gestion des requêtes plus simple et plus lisible. onreadystatechange est principalement utilisé lorsque vous avez besoin de suivre des états intermédiaires (comme la progression ou la réception des en-têtes).
L'événement load
L'événement load se déclenche une fois que la réponse est entièrement arrivée. Il est plus simple que onreadystatechange car vous n'avez pas à tester readyState vous-même : il ne se déclenche qu'à l'étape DONE. Vous devez tout de même vérifier status pour distinguer un vrai succès d'une erreur HTTP.
Exemple :
L'événement progress
Pour les téléchargements volumineux, vous pouvez signaler la progression avec l'événement progress. Lorsque le serveur envoie un en-tête Content-Length, l'événement est déterminé (lengthComputable vaut true) et vous pouvez calculer un pourcentage :
xhr.onprogress = function(event) {
if (event.lengthComputable) {
const percent = Math.round((event.loaded / event.total) * 100);
console.log(`Downloaded ${percent}%`);
}
};Pour suivre un upload à la place, attachez les gestionnaires à xhr.upload (xhr.upload.onprogress). L'objet de progression des uploads est la fonctionnalité que Fetch ne peut toujours pas pleinement reproduire.
Gérer les erreurs
Un code robuste doit gérer les échecs. Deux événements couvrent les cas d'échec :
onerrorse déclenche lors d'une défaillance au niveau réseau : la requête n'a jamais atteint le serveur, le DNS a échoué, CORS l'a bloquée, etc. Notez qu'une erreur HTTP404ou500n'est pas une erreur réseau : elle déclencheload, paserror, donc vous devez tout de même inspecterstatus.ontimeoutse déclenche si la requête prend plus dexhr.timeoutmillisecondes. Un timeout à0(la valeur par défaut) signifie aucune limite.
Exemple :
Parser les réponses JSON
Les réponses du serveur sont le plus souvent du JSON. L'approche la plus simple est de lire le texte brut depuis xhr.responseText et de le parser vous-même avec JSON.parse :
Alternativement, définissez xhr.responseType = 'json' avant l'envoi, et le navigateur parse le corps pour vous. La valeur parsée est alors disponible sur xhr.response (et non xhr.responseText) :
const xhr = new XMLHttpRequest();
xhr.open('GET', 'https://jsonplaceholder.typicode.com/posts/1', true);
xhr.responseType = 'json';
xhr.onload = function() {
if (xhr.status === 200) {
console.log('title: ' + xhr.response.title); // already an object
}
};
xhr.send();responseType accepte également 'text', 'blob', 'arraybuffer' et 'document' pour les données non-JSON.
Envoyer des données avec POST
Pour envoyer un corps JSON, définissez l'en-tête Content-Type et sérialisez votre objet avec JSON.stringify :
const xhr = new XMLHttpRequest();
xhr.open('POST', 'https://jsonplaceholder.typicode.com/posts', true);
xhr.setRequestHeader('Content-Type', 'application/json');
xhr.onload = function() {
if (xhr.status === 201) { // 201 Created
console.log('Created:', xhr.responseText);
}
};
xhr.send(JSON.stringify({ title: 'foo', body: 'bar', userId: 1 }));Pour des soumissions de formulaires traditionnelles, envoyez un objet FormData à la place : le navigateur définit automatiquement le bon Content-Type multipart, donc n'appelez pas setRequestHeader pour cela.
Annuler une requête
Appelez xhr.abort() pour annuler une requête en cours, par exemple lorsque l'utilisateur navigue ailleurs ou saisit une nouvelle requête de recherche. Après l'annulation, l'événement abort se déclenche à la place de load :
const xhr = new XMLHttpRequest();
xhr.open('GET', 'https://jsonplaceholder.typicode.com/posts', true);
xhr.onabort = () => console.log('Request was cancelled');
xhr.send();
// Later, cancel it:
xhr.abort();L'équivalent Fetch utilise un AbortController.
XMLHttpRequest vs Fetch
| XMLHttpRequest | Fetch | |
|---|---|---|
| Modèle de programmation | Callbacks / événements | Promesses, fonctionne avec await |
| Progression des uploads | Oui (xhr.upload) | Non |
| Progression des téléchargements | Oui (événement progress) | Via les streams (plus de code) |
| Annulation | xhr.abort() | AbortController |
| Rejet sur erreur HTTP | Non, vous vérifiez status | Non, vous vérifiez response.ok |
Pour la plupart des nouveaux codes, préférez Fetch. Recourez à XHR lorsque vous avez besoin d'un reporting granulaire de la progression des uploads ou que vous devez prendre en charge un environnement très ancien.
Conclusion
XMLHttpRequest permet à JavaScript d'échanger des données avec un serveur en arrière-plan : vous créez l'objet, vous l'ouvrez avec open, vous attachez des gestionnaires load/error/timeout, et vous l'envoyez avec send. N'oubliez pas de vérifier à la fois readyState et status, de parser le JSON vous-même ou via responseType, et d'utiliser abort() pour annuler les requêtes périmées. Pour la plupart des nouveaux codes, l'API Fetch basée sur les promesses est le meilleur choix par défaut, mais comprendre XHR vous rend à l'aise dans les bases de code plus anciennes et dans les cas, comme la progression des uploads, où il reste supérieur.