JavaScript peut envoyer des requĂȘtes rĂ©seau au serveur et charger de nouvelles informations chaque fois que nĂ©cessaire.
Par exemple, nous pouvons utiliser une requĂȘte rĂ©seau pour :
- Soumettre une commande,
- Charger des informations utilisateur,
- Recevoir les derniĂšres mises Ă jour du serveur,
- âŠetc.
⊠Et tout cela sans recharger la page !
Il y a un terme gĂ©nĂ©rique âAJAXâ (abrĂ©gĂ© de Asynchronous JavaScript And XML) pour les requĂȘtes rĂ©seau Ă partir de JavaScript. Cependant nous nâavons pas besoin dâutiliser XML : le terme vient de lâancien temps, câest pourquoi ce mot est lĂ . Vous avez peut-ĂȘtre dĂ©jĂ entendu ce terme.
Il existe plusieurs façons dâenvoyer une requĂȘte rĂ©seau et dâobtenir des informations du serveur.
La mĂ©thode fetch() est moderne et polyvalente, nous allons donc commencer avec celle-ci. Elle nâest pas prise en charge par les anciens navigateurs (peut ĂȘtre polyfilled), mais trĂšs bien prise en charge par les navigateurs modernes.
La syntaxe de base est :
let promise = fetch(url, [options])
urlâ lâURL cible.optionsâ paramĂštres facultatifs : mĂ©thode, en-tĂȘtes, etcâŠ
Sans options, câest une simple requĂȘte GET, tĂ©lĂ©chargeant le contenu de lâurl.
Le navigateur dĂ©marre la requĂȘte immĂ©diatement et renvoie une promesse que le code appelant devrait utiliser pour obtenir le rĂ©sultat.
Obtenir une réponse est généralement un processus en deux étapes.
PremiĂšrement, la promise, renvoyĂ©e par fetch, se rĂ©sout avec un objet de la classe intĂ©grĂ©e Response dĂšs que le serveur rĂ©pond avec des en-tĂȘtes.
Ă ce stade, nous pouvons vĂ©rifier lâĂ©tat HTTP, pour voir sâil est rĂ©ussi ou non, vĂ©rifier les en-tĂȘtes, mais nous ne disposons pas encore du corps.
La promesse rejette si le fetch nâa pas pu faire de requĂȘte HTTP, par exemple problĂšmes de rĂ©seau, ou si lâadresse nâexiste pas. Les statuts HTTP anormaux, tels que 404 ou 500, ne provoquent pas dâerreur.
Nous pouvons voir lâĂ©tat HTTP dans les propriĂ©tĂ©s de rĂ©ponse :
statusâ Code dâĂ©tat HTTP, par exemple 200.okâ boolĂ©en,truesi le code dâĂ©tat HTTP est 200-299.
Par exemple :
let response = await fetch(url);
if (response.ok) { // if HTTP-status is 200-299
// obtenir le corps de réponse (la méthode expliquée ci-dessous)
let json = await response.json();
} else {
alert("HTTP-Error: " + response.status);
}
DeuxiÚmement, pour obtenir le corps de la réponse, nous devons utiliser un appel de méthode supplémentaire.
Response fournit plusieurs méthodes basées sur les promesses pour accéder au corps dans différents formats :
response.text()â lit la rĂ©ponse et retourne sous forme de texte,response.json()â analyse la rĂ©ponse en JSON,response.formData()â retourne la rĂ©ponse en tant que objetFormData(expliquĂ© dans le chapitre suivant),response.blob()â retourne la rĂ©ponse en tant que Blob (donnĂ©e binaire avec type),response.arrayBuffer()â retourne la rĂ©ponse en tant que ArrayBuffer (reprĂ©sentation de bas niveau de donnĂ©e binaire),- aditionellement,
response.bodyest un objet ReadableStream, qui permet de lire le corps morceau par morceau, nous verrons un exemple plus tard.
Par exemple, obtenons un objet JSON avec les derniers commits de GitHub :
let url = 'https://api.github.com/repos/javascript-tutorial/en.javascript.info/commits';
let response = await fetch(url);
let commits = await response.json(); // lire le corps de réponse et analyser en JSON
alert(commits[0].author.login);
Ou, la mĂȘme chose sans await, en utilisant la syntaxe des promesses pures :
fetch('https://api.github.com/repos/javascript-tutorial/en.javascript.info/commits')
.then(response => response.json())
.then(commits => alert(commits[0].author.login));
Pour obtenir la réponse en texte, await response.text() au lieu de .json() :
let response = await fetch('https://api.github.com/repos/javascript-tutorial/en.javascript.info/commits');
let text = await response.text(); // lire le corps de la réponse sous forme de texte
alert(text.slice(0, 80) + '...');
En tant que vitrine pour la lecture au format binaire, rĂ©cupĂ©rons et affichons une image du logo de âfetchâ specification (voir le chapitre Blob pour plus de dĂ©tails sur les opĂ©rations de Blob):
let response = await fetch('/article/fetch/logo-fetch.svg');
let blob = await response.blob(); // télécharger en tant qu'objet Blob
// create <img> for it
let img = document.createElement('img');
img.style = 'position:fixed;top:10px;left:10px;width:100px';
document.body.append(img);
// l'afficher
img.src = URL.createObjectURL(blob);
setTimeout(() => { // le cacher aprĂšs 3 secondes
img.remove();
URL.revokeObjectURL(img.src);
}, 3000);
Nous ne pouvons choisir quâune seule mĂ©thode de lecture du corps.
Si nous avons déjà la réponse avec response.text(), alors response.json() ne fonctionnera pas, car le contenu du corps a déjà été traité.
let text = await response.text(); // corps de la réponse consommé
let parsed = await response.json(); // echec (déjà consommé)
En-tĂȘtes de rĂ©ponse
Les en-tĂȘtes de rĂ©ponse sont disponibles dans un objet dâen-tĂȘtes de type Map-like response.headers.
Ce nâest pas exactement un Map, mais il a des mĂ©thodes similaires pour obtenir des en-tĂȘtes individuels par nom ou les parcourir :
let response = await fetch('https://api.github.com/repos/javascript-tutorial/en.javascript.info/commits');
// get one header
alert(response.headers.get('Content-Type')); // application/json; charset=utf-8
// iterate over all headers
for (let [key, value] of response.headers) {
alert(`${key} = ${value}`);
}
En-tĂȘtes de requĂȘtes
Pour dĂ©finir un en-tĂȘte de requĂȘte dans fetch, nous pouvons utiliser lâoption headers. Il a un objet avec des en-tĂȘtes sortants, comme ceci :
let response = fetch(protectedUrl, {
headers: {
Authentication: 'secret'
}
});
⊠Mais il y a une liste dâen-tĂȘtes HTTP interdits que nous ne pouvons pas dĂ©finir :
Accept-Charset,Accept-EncodingAccess-Control-Request-HeadersAccess-Control-Request-MethodConnectionContent-LengthCookie,Cookie2DateDNTExpectHostKeep-AliveOriginRefererTETrailerTransfer-EncodingUpgradeViaProxy-*Sec-*
Ces en-tĂȘtes assurent un HTTP correct et sĂ»r, ils sont donc contrĂŽlĂ©s exclusivement par le navigateur.
RequĂȘtes POST
Pour faire une requĂȘte POST, ou une requĂȘte avec une autre mĂ©thode, nous devons utiliser les options fetch :
methodâ HTTP-method, par exemplePOST,bodyâ le corps de la requĂȘte, un parmi ceux-ci :- une chaĂźne de caractĂšres (par exemple encodĂ© en JSON),
- un objet
FormData, pour soumettre les données en tant quemultipart/form-data, Blob/BufferSourcepour envoyer des données binaires,- URLSearchParams, pour soumettre les données au format
x-www-form-urlencoded, rarement utilisé.
Le format JSON est utilisé la plupart du temps.
Par exemple, ce code soumet lâobjet user en JSON :
let user = {
name: 'John',
surname: 'Smith'
};
let response = await fetch('/article/fetch/post/user', {
method: 'POST',
headers: {
'Content-Type': 'application/json;charset=utf-8'
},
body: JSON.stringify(user)
});
let result = await response.json();
alert(result.message);
Veuillez noter que si la requĂȘte body est une chaĂźne de caractĂšres, alors lâen-tĂȘte Content-Type est dĂ©fini sur text/plain;charset=UTF-8 par dĂ©faut.
Mais, si nous envoyons du JSON, nous utiliserons Ă la place lâoption headers pour envoyer application/json, le bon Content-Type pour les donnĂ©es encodĂ©es en JSON.
Envoi dâune image
Nous pouvons également soumettre des données binaires avec fetch en utilisant des objets Blob ou BufferSource.
Dans cet exemple, il y a un <canvas> oĂč nous pouvons dessiner en dĂ©plaçant une souris dessus. Un clic sur le bouton âsubmitâ envoie lâimage au serveur :
<body style="margin:0">
<canvas id="canvasElem" width="100" height="80" style="border:1px solid"></canvas>
<input type="button" value="Submit" onclick="submit()">
<script>
canvasElem.onmousemove = function(e) {
let ctx = canvasElem.getContext('2d');
ctx.lineTo(e.clientX, e.clientY);
ctx.stroke();
};
async function submit() {
let blob = await new Promise(resolve => canvasElem.toBlob(resolve, 'image/png'));
let response = await fetch('/article/fetch/post/image', {
method: 'POST',
body: blob
});
// le serveur répond avec confirmation et la taille de l'image
let result = await response.json();
alert(result.message);
}
</script>
</body>
Veuillez noter quâici, nous ne dĂ©finissons pas lâen-tĂȘte Content-Type manuellement, car un objet Blob a un type intĂ©grĂ© (ici image/png, tel que gĂ©nĂ©rĂ© par toBlob). Pour les objets Blob, ce type devient la valeur de Content-Type.
La fonction submit() peut ĂȘtre réécrite sans async/await comme ceci :
function submit() {
canvasElem.toBlob(function(blob) {
fetch('/article/fetch/post/image', {
method: 'POST',
body: blob
})
.then(response => response.json())
.then(result => alert(JSON.stringify(result, null, 2)))
}, 'image/png');
}
Résumé
Une requĂȘte fetch typique se compose de deux appels await :
let response = await fetch(url, options); // se rĂ©sout avec des en-tĂȘtes de rĂ©ponse
let result = await response.json(); // lit le corps en tant que JSON
Ou, sans await :
fetch(url, options)
.then(response => response.json())
.then(result => /* process result */)
Propriétés de réponse :
response.statusâ Code HTTP de la rĂ©ponse,response.okâtrueest le statut 200-299.response.headersâ objet Map-like avec en-tĂȘtes HTTP.
Méthodes pour obtenir le corps de réponse :
response.text()â retourne la rĂ©ponse sous forme de texte,response.json()â analyse la rĂ©ponse en tant quâobjet JSON,response.formData()â retourne la rĂ©ponse en tant quâobjetFormData(encodagemultipart/form-data, voir le chapitre suivant),response.blob()â retourne la rĂ©ponse en tant que Blob (donnĂ©es binaires avec type),response.arrayBuffer()â retourne la rĂ©ponse en tant que ArrayBuffer (donnĂ©es binaires de bas niveau),
Options de fetch jusque lĂ :
methodâ MĂ©thode HTTP,headersâ un objet avec en-tĂȘtes de requĂȘte (aucun en-tĂȘte nâest autorisĂ©),bodyâ les donnĂ©es Ă envoyer (corps de la demande) en tant questring,FormData,BufferSource,Blobou objetUrlSearchParams.
Dans les chapitres suivants, nous verrons plus dâoptions et de cas dâutilisation de fetch.
Commentaires
<code>, pour plusieurs lignes â enveloppez-les avec la balise<pre>, pour plus de 10 lignes - utilisez une sandbox (plnkr, jsbin, codepenâŠ)