Prérequis
Description
L'Ajax ou Asynchronous Javascript and Xml est un outils indispensable du développeur web, qui permet d'envoyer des requêtes asynchrone vers des serveurs ou des api, et d'obtenir des résultats sans aucune perturbation pour l'utilisateur. Avec la montée en puissance des Api Rest ces dernières années, de plus en plus de site fonctionnent uniquement en communiquant via Ajax entre le frontend et le backend. Il est donc primordial de bien le connaitre et le comprendre pour devenir un développeur aguerri.
...
Euh oui, bonjour Arthur, qu'est ce qu'il y a?
Rien, je t'ai simplement envoyé un message asynchrone, il va arriver plus tard.
Ah bon? Pourquoi tu me parles d'asy...
[...]Salut, j'ai besoin de ton aide pour l'ajax, je n'y comprend rien !
Effectivement, je comprend mieux. Donc tu as des soucis pour mettre en place de l'ajax à ton travail?
Oui, je ne vois pas l'intérêt, je ne comprend même pas vraiment à quoi ça sert, à part que c'est asynchrone, donc que ça se fait plus tard.
Très bien, pour commencer on va juste préciser un détail, l'asynchrone ne signifie pas que ça va se réaliser plus tard, mais plutôt que tu pose une question, et tu dois attendre pour la réponse, mais pour autant tu peux faire autre chose en attendant.
Ah donc même ma blague n'était pas vraiment asynchrone?
Non pas vraiment. Tout d'abord, je vais refaire un point sur les requêtes http, tu en as déjà entendu parler?
Euh... c'est ce que l'on écrit dans une url tout au début je crois. http://
C'est bien ça, mais il y a une raison pour que l'on précise http au début d'une url, c'est tout le fonctionnement du web. En fait, pour communiquer entre différents ordinateurs, il faut utiliser ce que l'on appelle des protocoles de communication.
Je te crois sur parole.
Pour simplifier, c'est une façon de normaliser les communications, si on ne précise pas le protocole, une machine va envoyer un message en l'encodant d'une certaine façon, mais l'autre machine ne connait pas le protocole et ne sait donc pas décoder ce message pour le comprendre, et donc rien ne se passera comme prévu.
Ah je comprend ce que tu veux dire, c'est un peu comme si j'envoyais un message en français à un chinois sans lui expliquer qu'il faut le traduire.
Pas tout à fait, mais en quelque sorte oui. Donc pour en revenir à http, tu sais ce que ça veut dire?
Pas du tout
En fait http c'est une abréviation pour HyperText Transfert Protocole, ou si on le traduit en français, un protocole pour le transfert de données au format HyperText. Si je ne me trompe pas tu as déjà vu le mot HyperText ailleurs?
Ça me rapelle quelque chose... Ce ne serait pas dans html?
Tout à fait, html pour HyperText Markup Language, ou en français un langage de balisage HyperText. En fait le protocole http permet de communiquer en envoyant des données au format HyperText, et ce format est le plus souvent utilisé avec le html. Donc autrement dit http est un protocole qui permet d'accéder à des page html, donc des sites web.
Ok, ça me parait clair, mais je ne vois absolument pas le rapport avec l'Ajax...
Je vais y venir, fais moi confiance. On va d'abord apprendre à connaitre un peu mieux le protocole http, premièrement, le mode de communication est basé sur ce que l'on appelle des requêtes/réponses. C'est à dire que l'on va envoyer une question à une autre machine, c'est la requête, et celle ci va nous envoyer en retour une réponse.
Pour envoyer une requête, il faut tout d'abord savoir quel est le format des données pour communiquer en http. Rassure toi, je ne vais pas te décrire la liste complète, mais simplement les plus importants.
Une requête est composé au minimum d'une méthode et d'un message de requête. Pour la méthode, j'imagine que tu as déjà entendu parler de GET et de POST?
Oui, Get c'est quand on clique sur un lien, et POST c'est quand on envoie un formulaire
Alors c'est exact, mais c'est aussi plus large que ça, il existe bien plus de méthodes différentes, qui ont chacune un objectif différent. Pour ne te citer que les quatre les plus importantes il y a :
Avec ça, tu peux faire à peut près tout ce que tu veux en web.
Ok, je ne connaissais pas tout ça, mais effectivement ça me parait évident maintenant.
Et je t'ai donc aussi parlé d'un message de requête, parce que oui c'est bien de préciser la méthode GET pour dire que l'on veut récupérer une information, mais il faut préciser laquelle on veut, et c'est là qu'intervient le message et la norme URI.
Encore une autre norme? Mais je ne vais rien retenir à force...
Celle là tu la connais déjà, la norme URI, c'est celle qui définit le format des url, comme la barre d'adresse dans un navigateur web.
Ah ça me rassure
Et bien le protocole http utilise cette norme pour le message de requête. Par exemple si on souhaite récupérer l'image logo.png qui se trouve dans le dossier image on va envoyer la requête suivante :
Jai compris
Et bien tout ça, pour un utilisateur lambda c'est le navigateur web qui s'en occupe, quand tu saisie une adresse web dans la barre d'adresse, il envoie une requête http en GET pour récupérer les informations et te les afficher. Quand tu remplis un formulaire et que tu le valides, il envoie une requête POST au serveur pour lui demander d'enregistrer des données. Mais imaginons, tu veux envoyer une requête GET au clic sur un bouton de ton site, qui n'est pas un lien, ni un formulaire, ni rien de prévu dans le navigateur. Mais tu a besoins d'envoyer cette requête GET au clic sur ce bouton et rien d'autre. Comment vas-tu faire, vu que le navigateur ne le fait pas pour toi?
Avec une requête Ajax?
Exactement, la requête Ajax permet d'envoyer une requête http en précisant une méthode, une url et d'autres informations qui peuvent être utile. Et comprends-tu maintenant pourquoi on parle de requête asynchrone?
Parce que Ajax va envoyer la requête et ensuite il va attendre la réponse
Tout à fait, je précise tout de même une chose importante, il va attendre la réponse en continuant à exécuter d'autres portions de code. Il ne reste pas bloqué sur l'attente de cette réponse !
Donc, on va maintenant parler d'Ajax, si tu as bien compris les requêtes http, tu vas voir c'est assez simple. Pour commencer il faut créer une nouvelle requête grâce à l'objet javascript XmlHttpRequest
On lui ajoute notre message de requête et notre méthode avec la méthode open
notre requête est prête, il ne reste plus qu'à l'envoyer avec send
Pourquoi tu mets "null" dans la méthode send?
Parce que cette méthode permet d'envoyer des paramètres supplémentaires, mais dans notre cas, on a besoin de rien lui envoyer de plus, donc je met null. On y reviendra après tu verras.
Et du coup c'est tout? C'est juste ça une requête ajax?
Pas tout non, ça c'est l'envoie de la requête, il y a encore quelque chose que nous n'avons pas prévu c'est de récupérer la réponse de la requête. Pour cela, on utilise l'événement onreadystatechange de l'objet XmlHttpRequest. C'est un événement qui va se déclencher à chaque fois que l'état de la requête change.
Mais... Tu ne m'as jamais parlé d'un état de requête !
Je sais, ça n'avais pas vraiment d'intérêt avant donc je t'en parle maintenant. Une requête http peut avoir cinq états différents, numérotés de 0 à 4
Ok c'est clair
Donc on va ajouter un événement onreadystatechange sur cette requête pour pouvoir effectuer des traitements quand nous aurons la réponse.
mais pourquoi tu le mets avant d'envoyer la requête?
Parce qu'une requête ça peut aller très vite dans certains cas, et si on le met après, le temps que l'événement soit près, la requête aura pu avoir le temps de se finir, et donc ne jamais déclencher l'événement.
Maintenant, on a donc un événement qui va se déclencher quatre fois, car oui, par défaut la requête est déjà au statut 0 quand on la crée, il n'y a que les statuts suivants qui vont se déclencher. Nous ne sommes intéressés que par la réponse définitive de la requête, donc seul le statut 4 nous intéresse, les autres nous allons les passer dans notre cas. Pour cela, on va juste ajouter une condition sur ce statut à l'intérieur de notre événement.
Ainsi nos traitements ne s'effectueront que quand la requête est terminée.
Pourquoi tu as utilisé "this" pour récupérer le status?
Parce que l'événement est déclenché par la requête, donc à l'intérieur de cet événement, this représente la requête qui a déclenché le statut. On aurait pu utiliser request à la place, mais le jour où on lance plusieurs fois la même requête, à l'intérieur request ne représentera que la dernière qui a été lancée, en utilisant this, on est sur que l'on récupère le statut de celle qui vient de changer de statut, et pas une autre.
Il y a aussi autre chose d'intéressant dans la réponse dont nous allons avoir besoin, c'est le code de réponse.
Le code de réponse?
Oui comme, je te l'ai dit tout à l'heure, avec le protocole http, il y a beaucoup de type d'informations différentes, aussi bien à l'envoie de la requête qu'au retour de la requête. Entre autre un code de réponse, que l'on appelle code http. Tu dois déjà en connaitre quelques uns sans le savoir, si par exemple je te dit 404
Not Found !
Exactement, et bien le code 404 est un code http qui précise que le serveur n'as pas réussi à trouvé l'information que nous lui avons demandé. Il en existe beaucoup de différents, mais dans notre cas celui qui nous intéresse est le code 200, qui signifie "OK" la requête s'est bien passée sans aucune erreur. Il faut donc le combiner avec la vérification de statut, ainsi notre code ne s'exécutera que si la requête est terminée et qu'elle s'est bien passée.
Et voilà, il ne reste que deux points à voir pour que tu puisses commencer à utiliser des requêtes Ajax.
Ah bon? je pensais qu'on avait terminé !
Ce sont des détails, mais qui ont leur importance. Pour le premier, c'est simplement la récupération de la réponse du serveur, il y a une propriété dans la requête qui s'appelle responseText et qui contient le contenu de la réponse, on pourra donc l'exploiter comme ça :
Ok ça c'est simple et l'autre point?
Et bien nous n'avons vu que les requêtes GET pour le moment, pour les POST par exemple, il y a besoin d'informations en plus à envoyer avec la requête, qui contiennent les données que le serveur doit enregistrer.
Ah je crois comprendre, c'est ça qu'on va mettre dans le send?
Exactement ! Et on peut lui envoyer des données de beaucoup de formats différents, il faut juste vérifier quel format le serveur attend. Mais pour te donner quelques exemple.
En format url :
En format Json :
Avec un formdata et un input type file :
Et il en existe beaucoup d'autres !
Ok cette fois je pense que j'ai tout compris.
Une petite précision tout de même, ce que je t'ai montré là, c'est la base de l'utilisation d'Ajax, mais garde en mémoire que de nombreuses autres informations peuvent être envoyées avec la requête, comme le format de données que tu lui a envoyé avec content-type, ou un token d'accès avec authorization, et pareil pour le retour de la requête, il y a de nombreuses informations dans cette réponse qui peuvent être utiles dans certains cas !
Je retiens ça, un grand merci à toi pour ces explications !
Euh oui, bonjour Arthur, qu'est ce qu'il y a?
Rien, je t'ai simplement envoyé un message asynchrone, il va arriver plus tard.
Ah bon? Pourquoi tu me parles d'asy...
[...]Salut, j'ai besoin de ton aide pour l'ajax, je n'y comprend rien !
Effectivement, je comprend mieux. Donc tu as des soucis pour mettre en place de l'ajax à ton travail?
Oui, je ne vois pas l'intérêt, je ne comprend même pas vraiment à quoi ça sert, à part que c'est asynchrone, donc que ça se fait plus tard.
Très bien, pour commencer on va juste préciser un détail, l'asynchrone ne signifie pas que ça va se réaliser plus tard, mais plutôt que tu pose une question, et tu dois attendre pour la réponse, mais pour autant tu peux faire autre chose en attendant.
Ah donc même ma blague n'était pas vraiment asynchrone?
Non pas vraiment. Tout d'abord, je vais refaire un point sur les requêtes http, tu en as déjà entendu parler?
Euh... c'est ce que l'on écrit dans une url tout au début je crois. http://
C'est bien ça, mais il y a une raison pour que l'on précise http au début d'une url, c'est tout le fonctionnement du web. En fait, pour communiquer entre différents ordinateurs, il faut utiliser ce que l'on appelle des protocoles de communication.
Je te crois sur parole.
Pour simplifier, c'est une façon de normaliser les communications, si on ne précise pas le protocole, une machine va envoyer un message en l'encodant d'une certaine façon, mais l'autre machine ne connait pas le protocole et ne sait donc pas décoder ce message pour le comprendre, et donc rien ne se passera comme prévu.
Ah je comprend ce que tu veux dire, c'est un peu comme si j'envoyais un message en français à un chinois sans lui expliquer qu'il faut le traduire.
Pas tout à fait, mais en quelque sorte oui. Donc pour en revenir à http, tu sais ce que ça veut dire?
Pas du tout
En fait http c'est une abréviation pour HyperText Transfert Protocole, ou si on le traduit en français, un protocole pour le transfert de données au format HyperText. Si je ne me trompe pas tu as déjà vu le mot HyperText ailleurs?
Ça me rapelle quelque chose... Ce ne serait pas dans html?
Tout à fait, html pour HyperText Markup Language, ou en français un langage de balisage HyperText. En fait le protocole http permet de communiquer en envoyant des données au format HyperText, et ce format est le plus souvent utilisé avec le html. Donc autrement dit http est un protocole qui permet d'accéder à des page html, donc des sites web.
Ok, ça me parait clair, mais je ne vois absolument pas le rapport avec l'Ajax...
Je vais y venir, fais moi confiance. On va d'abord apprendre à connaitre un peu mieux le protocole http, premièrement, le mode de communication est basé sur ce que l'on appelle des requêtes/réponses. C'est à dire que l'on va envoyer une question à une autre machine, c'est la requête, et celle ci va nous envoyer en retour une réponse.
Pour envoyer une requête, il faut tout d'abord savoir quel est le format des données pour communiquer en http. Rassure toi, je ne vais pas te décrire la liste complète, mais simplement les plus importants.
Une requête est composé au minimum d'une méthode et d'un message de requête. Pour la méthode, j'imagine que tu as déjà entendu parler de GET et de POST?
Oui, Get c'est quand on clique sur un lien, et POST c'est quand on envoie un formulaire
Alors c'est exact, mais c'est aussi plus large que ça, il existe bien plus de méthodes différentes, qui ont chacune un objectif différent. Pour ne te citer que les quatre les plus importantes il y a :
- GET : pour demander à obtenir une information
- POST: pour demander la création d'une nouvelle donnée
- PUT: pour demander la modification d'une donnée
- DELETE: pour demander la suppression d'une donnée
Avec ça, tu peux faire à peut près tout ce que tu veux en web.
Ok, je ne connaissais pas tout ça, mais effectivement ça me parait évident maintenant.
Et je t'ai donc aussi parlé d'un message de requête, parce que oui c'est bien de préciser la méthode GET pour dire que l'on veut récupérer une information, mais il faut préciser laquelle on veut, et c'est là qu'intervient le message et la norme URI.
Encore une autre norme? Mais je ne vais rien retenir à force...
Celle là tu la connais déjà, la norme URI, c'est celle qui définit le format des url, comme la barre d'adresse dans un navigateur web.
Ah ça me rassure
Et bien le protocole http utilise cette norme pour le message de requête. Par exemple si on souhaite récupérer l'image logo.png qui se trouve dans le dossier image on va envoyer la requête suivante :
{"language":"shell","content":"GET /image/logo.png","filename":""}
Jai compris
Et bien tout ça, pour un utilisateur lambda c'est le navigateur web qui s'en occupe, quand tu saisie une adresse web dans la barre d'adresse, il envoie une requête http en GET pour récupérer les informations et te les afficher. Quand tu remplis un formulaire et que tu le valides, il envoie une requête POST au serveur pour lui demander d'enregistrer des données. Mais imaginons, tu veux envoyer une requête GET au clic sur un bouton de ton site, qui n'est pas un lien, ni un formulaire, ni rien de prévu dans le navigateur. Mais tu a besoins d'envoyer cette requête GET au clic sur ce bouton et rien d'autre. Comment vas-tu faire, vu que le navigateur ne le fait pas pour toi?
Avec une requête Ajax?
Exactement, la requête Ajax permet d'envoyer une requête http en précisant une méthode, une url et d'autres informations qui peuvent être utile. Et comprends-tu maintenant pourquoi on parle de requête asynchrone?
Parce que Ajax va envoyer la requête et ensuite il va attendre la réponse
Tout à fait, je précise tout de même une chose importante, il va attendre la réponse en continuant à exécuter d'autres portions de code. Il ne reste pas bloqué sur l'attente de cette réponse !
Donc, on va maintenant parler d'Ajax, si tu as bien compris les requêtes http, tu vas voir c'est assez simple. Pour commencer il faut créer une nouvelle requête grâce à l'objet javascript XmlHttpRequest
{"language":"application/json","content":"var request = new XmlHttpRequest();","filename":""}
On lui ajoute notre message de requête et notre méthode avec la méthode open
{"language":"application/json","content":"var request = new XmlHttpRequest();\nrequest.open(\"GET\",\"/image/logo.png\");","filename":""}
notre requête est prête, il ne reste plus qu'à l'envoyer avec send
{"language":"application/json","content":"var request = new XmlHttpRequest();\nrequest.open(\"GET\",\"/image/logo.png\");\nrequest.send(null);","filename":""}
Pourquoi tu mets "null" dans la méthode send?
Parce que cette méthode permet d'envoyer des paramètres supplémentaires, mais dans notre cas, on a besoin de rien lui envoyer de plus, donc je met null. On y reviendra après tu verras.
Et du coup c'est tout? C'est juste ça une requête ajax?
Pas tout non, ça c'est l'envoie de la requête, il y a encore quelque chose que nous n'avons pas prévu c'est de récupérer la réponse de la requête. Pour cela, on utilise l'événement onreadystatechange de l'objet XmlHttpRequest. C'est un événement qui va se déclencher à chaque fois que l'état de la requête change.
Mais... Tu ne m'as jamais parlé d'un état de requête !
Je sais, ça n'avais pas vraiment d'intérêt avant donc je t'en parle maintenant. Une requête http peut avoir cinq états différents, numérotés de 0 à 4
- 0 - UNSENT : la requête a été créé mais pas envoyée
- 1 - OPENED : la requête a été ouverte (avec la méthode open) mais toujours pas envoyée
- 2 - HEADERS_RECEIVED : la requête a été envoyée et le serveur a reçu les en-têtes
- 3 - LOADING : la requête a été traitée et le serveur commence à nous envoyer une réponse
- 4 - DONE : la requête est terminée et nous avons reçu la réponse
Ok c'est clair
Donc on va ajouter un événement onreadystatechange sur cette requête pour pouvoir effectuer des traitements quand nous aurons la réponse.
{"language":"application/json","content":"var request = new XmlHttpRequest();\n\nrequest.onreadystatechange = function(){\n\t//les traitements à effectuer quand on a la réponse\t\n}\nrequest.open(\"GET\",\"/image/logo.png\");\nrequest.send(null);","filename":""}
mais pourquoi tu le mets avant d'envoyer la requête?
Parce qu'une requête ça peut aller très vite dans certains cas, et si on le met après, le temps que l'événement soit près, la requête aura pu avoir le temps de se finir, et donc ne jamais déclencher l'événement.
Maintenant, on a donc un événement qui va se déclencher quatre fois, car oui, par défaut la requête est déjà au statut 0 quand on la crée, il n'y a que les statuts suivants qui vont se déclencher. Nous ne sommes intéressés que par la réponse définitive de la requête, donc seul le statut 4 nous intéresse, les autres nous allons les passer dans notre cas. Pour cela, on va juste ajouter une condition sur ce statut à l'intérieur de notre événement.
{"language":"application/json","content":"var request = new XmlHttpRequest();\nrequest.onreadystatechange = function(){\n\tif(this.readyState == 4){\n\t\t//les traitements à effectuer quand on a la réponse\n\t}\n}\nrequest.open(\"GET\",\"/image/logo.png\");\nrequest.send(null);","filename":""}
Ainsi nos traitements ne s'effectueront que quand la requête est terminée.
Pourquoi tu as utilisé "this" pour récupérer le status?
Parce que l'événement est déclenché par la requête, donc à l'intérieur de cet événement, this représente la requête qui a déclenché le statut. On aurait pu utiliser request à la place, mais le jour où on lance plusieurs fois la même requête, à l'intérieur request ne représentera que la dernière qui a été lancée, en utilisant this, on est sur que l'on récupère le statut de celle qui vient de changer de statut, et pas une autre.
Il y a aussi autre chose d'intéressant dans la réponse dont nous allons avoir besoin, c'est le code de réponse.
Le code de réponse?
Oui comme, je te l'ai dit tout à l'heure, avec le protocole http, il y a beaucoup de type d'informations différentes, aussi bien à l'envoie de la requête qu'au retour de la requête. Entre autre un code de réponse, que l'on appelle code http. Tu dois déjà en connaitre quelques uns sans le savoir, si par exemple je te dit 404
Not Found !
Exactement, et bien le code 404 est un code http qui précise que le serveur n'as pas réussi à trouvé l'information que nous lui avons demandé. Il en existe beaucoup de différents, mais dans notre cas celui qui nous intéresse est le code 200, qui signifie "OK" la requête s'est bien passée sans aucune erreur. Il faut donc le combiner avec la vérification de statut, ainsi notre code ne s'exécutera que si la requête est terminée et qu'elle s'est bien passée.
{"language":"application/json","content":"var request = new XmlHttpRequest();\nrequest.onreadystatechange = function(){\n\tif(this.readyState == 4 && this.status == 200){\n\t\t//les traitements à effectuer quand on a la réponse\n\t}\n}\nrequest.open(\"GET\",\"/image/logo.png\");\nrequest.send(null);\n","filename":""}
Et voilà, il ne reste que deux points à voir pour que tu puisses commencer à utiliser des requêtes Ajax.
Ah bon? je pensais qu'on avait terminé !
Ce sont des détails, mais qui ont leur importance. Pour le premier, c'est simplement la récupération de la réponse du serveur, il y a une propriété dans la requête qui s'appelle responseText et qui contient le contenu de la réponse, on pourra donc l'exploiter comme ça :
{"language":"application/json","content":"var request = new XmlHttpRequest();\nrequest.onreadystatechange = function(){\n\tif(this.readyState == 4 && this.status == 200){\n\t\tconsole.log(this.responseText);\n\t}\n}\nrequest.open(\"GET\",\"/image/logo.png\");\nrequest.send(null);\n","filename":""}
Ok ça c'est simple et l'autre point?
Et bien nous n'avons vu que les requêtes GET pour le moment, pour les POST par exemple, il y a besoin d'informations en plus à envoyer avec la requête, qui contiennent les données que le serveur doit enregistrer.
Ah je crois comprendre, c'est ça qu'on va mettre dans le send?
Exactement ! Et on peut lui envoyer des données de beaucoup de formats différents, il faut juste vérifier quel format le serveur attend. Mais pour te donner quelques exemple.
En format url :
{"language":"application/json","content":"var request = new XmlHttpRequest();\nrequest.onreadystatechange = function(){\n\tif(this.readyState == 4 && this.status == 200){\n\t\tconsole.log(this.responseText);\n\t}\n}\nrequest.open(\"GET\",\"/image/logo.png\");\nrequest.send(\"id=1&page=3\");","filename":""}
En format Json :
{"language":"application/json","content":"var request = new XmlHttpRequest();\nrequest.onreadystatechange = function(){\n\tif(this.readyState == 4 && this.status == 200){\n\t\tconsole.log(this.responseText);\n\t}\n}\nvar data = {\n\tid: 1,\n\tpage: 3\n}\n\nrequest.open(\"POST\",\"/image/logo.png\");\nrequest.send(JSON.stringify(data));","filename":""}
Avec un formdata et un input type file :
{"language":"application/json","content":"var request = new XmlHttpRequest();\nrequest.onreadystatechange = function(){\n\tif(this.readyState == 4 && this.status == 200){\n\t\tconsole.log(this.responseText);\n\t}\n}\nvar data = new FormData();\ndata.append(\"image\", document.getElementById(\"input-file\").files[0]);\n\nrequest.open(\"POST\",\"/image/logo.png\");\nrequest.send(data);","filename":""}
Et il en existe beaucoup d'autres !
Ok cette fois je pense que j'ai tout compris.
Une petite précision tout de même, ce que je t'ai montré là, c'est la base de l'utilisation d'Ajax, mais garde en mémoire que de nombreuses autres informations peuvent être envoyées avec la requête, comme le format de données que tu lui a envoyé avec content-type, ou un token d'accès avec authorization, et pareil pour le retour de la requête, il y a de nombreuses informations dans cette réponse qui peuvent être utiles dans certains cas !
Je retiens ça, un grand merci à toi pour ces explications !
Commentaires