Movatterモバイル変換


[0]ホーム

URL:


  1. Web
  2. Les API Web
  3. API Fetch
  4. Utiliser l'API Fetch

Cette page a été traduite à partir de l'anglais par la communauté.Vous pouvez contribuer en rejoignant la communauté francophone sur MDN Web Docs.

View in EnglishAlways switch to English

Utiliser l'API Fetch

L'API Fetch fournit une interface JavaScript pour effectuer des requêtes HTTP et traiter les réponses.

Fetch est le remplaçant moderne deXMLHttpRequest : contrairement àXMLHttpRequest, qui utilise des fonctions de rappel, Fetch est basé sur les promesses et s'intègre avec les fonctionnalités du web moderne telles que lesservice workers et lepartage des ressources entre origines (CORS).

Avec l'API Fetch, vous effectuez une requête en appelantfetch(), qui est disponible en tant que fonction globale dans les contexteswindow etworker. Vous lui passez un objetRequest ou une chaîne contenant l'URL à récupérer, ainsi qu'un argument optionnel pour configurer la requête.

La fonctionfetch() retourne une promesse (Promise) qui est résolue avec un objetResponse représentant la réponse du serveur. Vous pouvez alors vérifier le statut de la requête et extraire le corps de la réponse dans différents formats, y compris texte et JSON, en appelant la méthode appropriée sur la réponse.

Voici une fonction minimale qui utilisefetch() pour récupérer des données JSON depuis un serveur :

js
async function getData() {  const url = "https://exemple.org/produits.json";  try {    const reponse = await fetch(url);    if (!reponse.ok) {      throw new Error(`Statut de réponse : ${reponse.status}`);    }    const resultat = await reponse.json();    console.log(resultat);  } catch (erreur) {    console.error(erreur.message);  }}

Nous déclarons une chaîne de caractères contenant l'URL puis appelonsfetch(), en passant l'URL sans options supplémentaires.

La fonctionfetch() rejettera la promesse en cas de certaines erreurs, mais pas si le serveur répond avec un statut d'erreur comme404 : nous vérifions donc aussi le statut de la réponse et lançons une exception si ce n'est pas OK.

Sinon, nous récupérons le contenu du corps de la réponse au formatJSON en appelant la méthodejson() de l'interfaceResponse, et affichons l'une de ses valeurs. Notez que, commefetch() elle-même,json() est asynchrone, tout comme toutes les autres méthodes d'accès au contenu du corps de la réponse.

Dans la suite de cette page, nous examinerons plus en détail les différentes étapes de ce processus.

Effectuer une requête

Pour effectuer une requête, appelezfetch() en passant :

  1. une définition de la ressource à récupérer. Cela peut être :
  2. éventuellement, un objet contenant des options pour configurer la requête.

Dans cette section, nous allons regarder certaines des options les plus couramment utilisées. Pour lire toutes les options qui peuvent être données, voir la page de référence de la méthodefetch().

Définir la méthode

Par défaut,fetch() effectue une requêteGET, mais vous pouvez utiliser l'optionmethod pour utiliser uneméthode de requête différente :

js
const reponse = await fetch("https://exemple.org/post", {  method: "POST",  // …});

Si l'optionmode est définie surno-cors, alorsmethod doit être l'une des valeursGET,POST ouHEAD.

Définir un corps de requête

Le corps de la requête est la charge utile de la requête : c'est ce que le client envoie au serveur. Vous ne pouvez pas inclure de corps avec les requêtesGET, mais c'est utile pour les requêtes qui envoient du contenu au serveur, comme les requêtesPOST ouPUT. Par exemple, si vous souhaitez téléverser un fichier vers le serveur, vous pouvez effectuer une requêtePOST et inclure le fichier comme corps de la requête.

Pour définir un corps de requête, passez-le en optionbody :

js
const reponse = await fetch("https://exemple.org/post", {  method: "POST",  body: JSON.stringify({ username: "exemple" }),  // …});

Vous pouvez fournir le corps comme une instance de l'un des types suivants :

Les autres objets sont convertis en chaînes de caractères à l'aide de leur méthodetoString(). Par exemple, vous pouvez utiliser un objetURLSearchParams pour encoder des données de formulaire (voirDéfinir les en-têtes pour plus d'informations) :

js
const reponse = await fetch("https://exemple.org/post", {  method: "POST",  headers: {    "Content-Type": "application/x-www-form-urlencoded",  },  // Automatiquement converti en "username=exemple&password=motdepasse"  body: new URLSearchParams({ username: "exemple", password: "motdepasse" }),  // …});

Notez que, tout comme les corps de réponse, les corps de requête sont des flux, et effectuer la requête lit le flux, donc si une requête contient un corps, vous ne pouvez pas l'utiliser deux fois :

js
const requete = new Request("https://exemple.org/post", {  method: "POST",  body: JSON.stringify({ username: "exemple" }),});const reponse1 = await fetch(requete);console.log(reponse1.status);// Provoquera une erreur : "Body has already been consumed."const reponse2 = await fetch(requete);console.log(reponse2.status);

À la place, vous devrezcréer un clone de la requête avant de l'envoyer :

js
const requete1 = new Request("https://exemple.org/post", {  method: "POST",  body: JSON.stringify({ username: "exemple" }),});const requete2 = requete1.clone();const reponse1 = await fetch(requete1);console.log(reponse1.status);const reponse2 = await fetch(requete2);console.log(reponse2.status);

Voirles flux verrouillés et perturbés pour plus d'informations.

Définir les en-têtes

Les en-têtes de requête fournissent au serveur des informations sur la requête : par exemple, dans une requêtePOST, l'en-têteContent-Type indique au serveur le format du corps de la requête.

Pour définir des en-têtes de requête, assignez-les à l'optionheaders.

Vous pouvez passer ici un objet littéral contenant des propriétésnom-en-tête: valeur-en-tête :

js
const reponse = await fetch("https://exemple.org/post", {  method: "POST",  headers: {    "Content-Type": "application/json",  },  body: JSON.stringify({ username: "exemple" }),  // …});

Vous pouvez aussi construire un objetHeaders, ajouter des en-têtes à cet objet avecHeaders.append(), puis assigner l'objetHeaders à l'optionheaders :

js
const mesEntetes = new Headers();mesEntetes.append("Content-Type", "application/json");const reponse = await fetch("https://exemple.org/post", {  method: "POST",  headers: mesEntetes,  body: JSON.stringify({ username: "exemple" }),  // …});

Comparé à l'utilisation d'objets simples, l'objetHeaders fournit une validation supplémentaire des entrées. Par exemple, il normalise les noms d'en-tête en minuscules, supprime les espaces en début et fin de valeur, et empêche certains en-têtes d'être définis. De nombreux en-têtes sont définis automatiquement par le navigateur et ne peuvent pas être définis par un script : ce sont lesen-têtes de requête interdits. Si l'optionmode est définie surno-cors, l'ensemble des en-têtes autorisés est encore plus restreint.

Envoyer des données dans une requête GET

Les requêtesGET n'ont pas de corps, mais vous pouvez tout de même envoyer des données au serveur en les ajoutant à l'URL sous forme de chaîne de requête. C'est une façon courante d'envoyer des données de formulaire au serveur. Vous pouvez le faire en utilisantURLSearchParams pour encoder les données, puis en les ajoutant à l'URL :

js
const params = new URLSearchParams();params.append("username", "exemple");// Requête GET envoyée à https://exemple.org/login?username=exempleconst reponse = await fetch(`https://exemple.org/login?${params}`);

Effectuer des requêtes inter-origines

La possibilité d'effectuer une requête inter-origines est déterminée par la valeur de l'optionRequestInit.mode. Cette option peut prendre l'une des trois valeurs suivantes :cors,same-origin ouno-cors.

  • Pour les requêtes fetch, la valeur par défaut demode estcors, ce qui signifie que si la requête est inter-origines, elle utilisera le mécanisme departage des ressources entre origines (CORS). Cela signifie :

    • si la requête est unerequête simple, la requête sera toujours envoyée, mais le serveur doit répondre avec l'en-têteAccess-Control-Allow-Origin approprié, sinon le navigateur ne partagera pas la réponse avec l'appelant.
    • si la requête n'est pas une requête simple, le navigateur enverra unerequête de pré-vérification pour vérifier que le serveur comprend CORS et autorise la requête, et la requête réelle ne sera envoyée que si le serveur répond à la requête de pré-vérification avec les en-têtes CORS appropriés.
  • Définirmode sursame-origin interdit complètement les requêtes inter-origines.

  • Définirmode surno-cors désactive CORS pour les requêtes inter-origines. Cela restreint les en-têtes qui peuvent être définis et limite les méthodes à GET, HEAD et POST. La réponse estopaque, ce qui signifie que ses en-têtes et son corps ne sont pas accessibles en JavaScript. La plupart du temps, un site web ne devrait pas utiliserno-cors : son principal usage concerne certains cas d'utilisation des service workers.

Voir la documentation de référence pourRequestInit.mode pour plus de détails.

Inclure des informations d'authentification

Dans le contexte de l'API Fetch, une information d'authentification est une donnée supplémentaire envoyée avec la requête que le serveur peut utiliser pour authentifier l'utilisateur·ice. Tous les éléments suivants sont considérés comme des informations d'authentification :

Par défaut, les informations d'authentification ne sont incluses que dans les requêtes de même origine. Pour personnaliser ce comportement, ainsi que pour contrôler si le navigateur respecte les en-têtes de réponseSet-Cookie, définissez l'optioncredentials, qui peut prendre l'une des trois valeurs suivantes :

  • omit : n'envoie jamais d'informations d'authentification dans la requête et n'en inclut pas dans la réponse.
  • same-origin (valeur par défaut) : n'envoie et n'inclut les informations d'authentification que pour les requêtes de même origine.
  • include : inclut toujours les informations d'authentification, même pour les requêtes inter-origines.

Notez que si l'attributSameSite d'un cookie est défini surStrict ouLax, alors le cookie ne sera pas envoyé entre sites, même sicredentials est défini surinclude.

Inclure des informations d'authentification dans des requêtes inter-origines peut rendre un site vulnérable aux attaques de typeCSRF. Ainsi, même sicredentials est défini surinclude, le serveur doit également accepter leur inclusion en ajoutant l'en-têteAccess-Control-Allow-Credentials dans sa réponse. De plus, dans ce cas, le serveur doit définir explicitement l'origine du client dans l'en-tête de réponseAccess-Control-Allow-Origin (c'est-à-dire que* n'est pas autorisé).

Cela signifie que sicredentials est défini surinclude et que la requête est inter-origines :

  • Si la requête est unerequête simple, alors la requête sera envoyée avec les informations d'authentification, mais le serveur doit définir les en-têtes de réponseAccess-Control-Allow-Credentials etAccess-Control-Allow-Origin, sinon le navigateur retournera une erreur réseau à l'appelant. Si le serveur définit les bons en-têtes, alors la réponse, y compris les informations d'authentification, sera transmise à l'appelant.

  • Si la requête n'est pas une requête simple, alors le navigateur enverra unerequête de pré-vérification sans informations d'authentification, et le serveur doit définir les en-têtes de réponseAccess-Control-Allow-Credentials etAccess-Control-Allow-Origin, sinon le navigateur retournera une erreur réseau à l'appelant. Si le serveur définit les bons en-têtes, alors le navigateur poursuivra avec la requête réelle, y compris les informations d'authentification, et transmettra la réponse réelle, y compris les informations d'authentification, à l'appelant.

Créer un objetRequest

Le constructeurRequest() prend les mêmes arguments quefetch() lui-même. Cela signifie qu'au lieu de passer des options àfetch(), vous pouvez passer les mêmes options au constructeurRequest(), puis passer cet objet àfetch().

Par exemple, on peut effectuer une requête POST en passant des options àfetch() avec un code comme celui-ci :

js
const mesEntetes = new Headers();mesEntetes.append("Content-Type", "application/json");const reponse = await fetch("https://exemple.org/post", {  method: "POST",  body: JSON.stringify({ username: "exemple" }),  headers: mesEntetes,});

Cependant, on peut réécrire cela pour passer les mêmes arguments au constructeurRequest() :

js
const mesEntetes = new Headers();mesEntetes.append("Content-Type", "application/json");const maRequete = new Request("https://exemple.org/post", {  method: "POST",  body: JSON.stringify({ username: "exemple" }),  headers: mesEntetes,});const reponse = await fetch(maRequete);

Cela signifie aussi que vous pouvez créer une requête à partir d'une autre requête, tout en modifiant certaines de ses propriétés à l'aide du second argument :

js
async function post(requete) {  try {    const reponse = await fetch(requete);    const resultat = await reponse.json();    console.log("Réussite :", resultat);  } catch (erreur) {    console.error("Erreur :", erreur);  }}const requete1 = new Request("https://exemple.org/post", {  method: "POST",  headers: {    "Content-Type": "application/json",  },  body: JSON.stringify({ username: "exemple1" }),});const requete2 = new Request(requete1, {  body: JSON.stringify({ username: "exemple2" }),});post(requete1);post(requete2);

Interrompre une requête

Pour rendre une requête annulable, créez unAbortController, et assignez sonAbortSignal à la propriétésignal de la requête.

Pour annuler la requête, appelez la méthodeabort() du contrôleur. L'appel àfetch() rejettera la promesse avec une exceptionAbortError.

js
const controleur = new AbortController();const btnRecuperation = document.querySelector("#fetch");btnRecuperation.addEventListener("click", async () => {  try {    console.log("Début de la récupération");    const reponse = await fetch("https://exemple.org/get", {      signal: controleur.signal,    });    console.log(`Réponse : ${reponse.status}`);  } catch (e) {    console.error(`Erreur : ${e}`);  }});const btnAnnuler = document.querySelector("#cancel");btnAnnuler.addEventListener("click", () => {  controleur.abort();  console.log("Récupération annulée");});

Si la requête est annulée après que l'appel àfetch() a été accompli mais avant que le corps de la réponse n'ait été lu, alors toute tentative de lecture du corps de la réponse rejettera avec une exceptionAbortError.

js
async function recuperer() {  const controleur = new AbortController();  const requete = new Request("https://exemple.org/get", {    signal: controleur.signal,  });  const reponse = await fetch(requete);  controleur.abort();  // La ligne suivante va lever une exception `AbortError`  const texte = await reponse.text();  console.log(texte);}

Traiter la réponse

Dès que le navigateur a reçu le statut de la réponse et les en-têtes du serveur (et potentiellement avant que le corps de la réponse lui-même ait été reçu), la promesse retournée parfetch() est tenue avec un objetResponse.

Vérifier le statut de la réponse

La promesse retournée parfetch() sera rejetée en cas de certaines erreurs, comme une erreur réseau ou un mauvais schéma. Cependant, si le serveur répond avec une erreur comme404, alorsfetch() est tenue avec un objetResponse, il faut donc vérifier le statut avant de lire le corps de la réponse.

La propriétéResponse.status donne le code de statut numérique, et la propriétéResponse.ok retournetrue si le statut est dans laplage 200.

Un schéma courant consiste à vérifier la valeur deok et à lancer une exception si elle vautfalse :

js
async function obtenirDonnees() {  const url = "https://exemple.org/produits.json";  try {    const reponse = await fetch(url);    if (!reponse.ok) {      throw new Error(`Statut de réponse : ${reponse.status}`);    }    // …  } catch (erreur) {    console.error(erreur.message);  }}

Vérifier le type de la réponse

Les réponses possèdent une propriététype qui peut avoir l'une des valeurs suivantes :

  • basic : la requête était de même origine.
  • cors : la requête était une requête CORS inter-origines.
  • opaque : la requête était une requête simple inter-origines effectuée avec le modeno-cors.
  • opaqueredirect : la requête a défini l'optionredirect surmanual, et le serveur a retourné unstatut de redirection.

Le type détermine le contenu possible de la réponse, comme suit :

Vérifier les en-têtes

Comme pour la requête, la réponse possède une propriétéheaders qui est un objetHeaders, et celui-ci contient tous les en-têtes de réponse exposés aux scripts, sous réserve des exclusions selon le type de réponse.

Un cas d'usage courant consiste à vérifier le type de contenu avant d'essayer de lire le corps :

js
async function recupererJSON(requete) {  try {    const reponse = await fetch(requete);    const typeContenu = reponse.headers.get("content-type");    if (!typeContenu || !typeContenu.includes("application/json")) {      throw new TypeError("Oups, ce n'est pas du JSON !");    }    // Sinon, on peut lire le corps en JSON  } catch (erreur) {    console.error("Erreur :", erreur);  }}

Lire le corps de la réponse

L'interfaceResponse fournit plusieurs méthodes pour récupérer l'intégralité du contenu du corps dans différents formats :

Toutes ces méthodes sont asynchrones et retournent une promesse (Promise) qui sera tenue avec le contenu du corps.

Dans cet exemple, on récupère une image et on la lit comme unBlob, que l'on peut ensuite utiliser pour créer une URL d'objet :

js
const image = document.querySelector("img");const url = "fleurs.jpg";async function definirImage() {  try {    const reponse = await fetch(url);    if (!reponse.ok) {      throw new Error(`Statut de réponse : ${reponse.status}`);    }    const blob = await reponse.blob();    const urlObjet = URL.createObjectURL(blob);    image.src = urlObjet;  } catch (e) {    console.error(e);  }}

La méthode lancera une exception si le corps de la réponse n'est pas dans le format approprié : par exemple, si vous appelezjson() sur une réponse qui ne peut pas être analysée comme JSON.

Lire le corps de la réponse en flux

Les corps de requête et de réponse sont en réalité des objetsReadableStream, et chaque fois que vous les lisez, vous traitez le contenu en flux. Cela est avantageux pour la gestion de la mémoire, car le navigateur n'a pas besoin de mettre en mémoire tampon toute la réponse avant que l'appelant la récupère avec une méthode commejson().

Cela signifie aussi que l'appelant peut traiter le contenu de façon incrémentale au fur et à mesure qu'il est reçu.

Par exemple, considérez une requêteGET qui récupère un grand fichier texte et le traite d'une certaine manière, ou l'affiche à l'utilisateur·ice :

js
const url = "https://www.exemple.org/un-gros-fichier.txt";async function recupererTexte(url) {  try {    const reponse = await fetch(url);    if (!reponse.ok) {      throw new Error(`Statut de réponse : ${reponse.status}`);    }    const texte = await reponse.text();    console.log(texte);  } catch (e) {    console.error(e);  }}

Si on utiliseResponse.text(), comme ci-dessus, il faut attendre que tout le fichier soit reçu avant de pouvoir en traiter une partie.

Si on lit la réponse en flux, on peut traiter des morceaux du corps au fur et à mesure qu'ils sont reçus du réseau :

js
const url = "https://www.exemple.org/un-gros-fichier.txt";async function recupererTexteEnFlux(url) {  try {    const reponse = await fetch(url);    if (!reponse.ok) {      throw new Error(`Statut de réponse : ${reponse.status}`);    }    const flux = reponse.body.pipeThrough(new TextDecoderStream());    for await (const valeur of flux) {      console.log(valeur);    }  } catch (e) {    console.error(e);  }}

Dans cet exemple, onitère de façon asynchrone sur le flux, en traitant chaque morceau à mesure qu'il arrive.

Notez que lorsque vous accédez directement au corps de cette façon, vous obtenez les octets bruts de la réponse et devez les transformer vous-même. Ici, on appelleReadableStream.pipeThrough() pour faire passer la réponse dans unTextDecoderStream, qui décode les données du corps encodées en UTF-8 en texte.

Traiter un fichier texte ligne par ligne

Dans l'exemple ci-dessous, on récupère une ressource texte et on la traite ligne par ligne, en utilisant une expression régulière pour détecter les fins de ligne. Par simplicité, on suppose que le texte est en UTF-8 et on ne gère pas les erreurs de récupération :

js
async function* iterateurLignesFichierTexte(urlFichier) {  const reponse = await fetch(urlFichier);  const lecteur = reponse.body.pipeThrough(new TextDecoderStream()).getReader();  let { value: bloc = "", done: lecteurTermine } = await lecteur.read();  const sautDeLigne = /\r?\n/g;  let debutIndex = 0;  while (true) {    const resultat = sautDeLigne.exec(bloc);    if (!resultat) {      if (lecteurTermine) break;      const reste = bloc.slice(debutIndex);      ({ value: bloc, done: lecteurTermine } = await lecteur.read());      bloc = reste + (bloc || "");      debutIndex = sautDeLigne.lastIndex = 0;      continue;    }    yield bloc.substring(debutIndex, resultat.index);    debutIndex = sautDeLigne.lastIndex;  }  if (debutIndex < bloc.length) {    // La dernière ligne ne se termine pas par un caractère de saut de ligne    yield bloc.substring(debutIndex);  }}async function executer(urlDuFichier) {  for await (const ligne of iterateurLignesFichierTexte(urlDuFichier)) {    traiterLigne(ligne);  }}function traiterLigne(ligne) {  console.log(ligne);}executer("https://www.exemple.org/un-gros-fichier.txt");

Flux verrouillés et perturbés

Les conséquences du fait que les corps de requête et de réponse sont des flux sont les suivantes :

  • si un lecteur a été attaché à un flux avecReadableStream.getReader(), alors le flux estverrouillé, et rien d'autre ne peut lire le flux.
  • si du contenu a été lu depuis le flux, alors le flux estperturbé, et rien d'autre ne peut lire depuis le flux.

Cela signifie qu'il n'est pas possible de lire le même corps de réponse (ou de requête) plus d'une fois :

js
async function obtenirDonnees() {  const url = "https://exemple.org/produits.json";  try {    const reponse = await fetch(url);    if (!reponse.ok) {      throw new Error(`Statut de réponse : ${reponse.status}`);    }    const resultat1 = await reponse.json();    const resultat2 = await reponse.json(); // va lancer une exception  } catch (erreur) {    console.error(erreur.message);  }}

Si vous devez lire le corps plus d'une fois, vous devez appelerResponse.clone() avant de lire le corps :

js
async function obtenirDonnees() {  const url = "https://exemple.org/produits.json";  try {    const reponse1 = await fetch(url);    if (!reponse1.ok) {      throw new Error(`Statut de réponse : ${reponse1.status}`);    }    const reponse2 = reponse1.clone();    const resultat1 = await reponse1.json();    const resultat2 = await reponse2.json();  } catch (erreur) {    console.error(erreur.message);  }}

C'est un schéma courant lors dela mise en œuvre d'un cache hors ligne avec les service workers. Le service worker souhaite retourner la réponse à l'application, mais aussi mettre la réponse en cache. Il clone donc la réponse, retourne l'originale et met le clone en cache :

js
async function cacheEnPremier(requete) {  const reponseEnCache = await caches.match(requete);  if (reponseEnCache) {    return reponseEnCache;  }  try {    const reponseReseau = await fetch(requete);    if (reponseReseau.ok) {      const cache = await caches.open("MonCache_1");      cache.put(requete, reponseReseau.clone());    }    return reponseReseau;  } catch (erreur) {    return Response.error();  }}self.addEventListener("fetch", (event) => {  if (ressourcesPrecachees.includes(url.pathname)) {    event.respondWith(cacheEnPremier(event.request));  }});

Voir aussi

Help improve MDN

Learn how to contribute

Cette page a été modifiée le par lescontributeurs du MDN.


[8]ページ先頭

©2009-2026 Movatter.jp