[ Web Proxy ]
URL:
Viewing: https://developer.mozilla.org/fr/docs/Web/API/Fetch_API/Using_Fetch [Back]  [Original]

Utiliser l'API Fetch - Les API Web | MDN

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 English Always switch to English

Utiliser l'API Fetch

L'API Fetch fournit une interface JavaScript pour effectuer des requtes HTTP et traiter les rponses.

Fetch est le remplaant moderne de XMLHttpRequest : contrairement XMLHttpRequest, qui utilise des fonctions de rappel, Fetch est bas sur les promesses et s'intgre avec les fonctionnalits du web moderne telles que les service workers et le partage des ressources entre origines (CORS).

Avec l'API Fetch, vous effectuez une requte en appelant fetch(), qui est disponible en tant que fonction globale dans les contextes window et worker. Vous lui passez un objet Request ou une chane contenant l'URL rcuprer, ainsi qu'un argument optionnel pour configurer la requte.

La fonction fetch() retourne une promesse (Promise) qui est rsolue avec un objet Response reprsentant la rponse du serveur. Vous pouvez alors vrifier le statut de la requte et extraire le corps de la rponse dans diffrents formats, y compris texte et JSON, en appelant la mthode approprie sur la rponse.

Voici une fonction minimale qui utilise fetch() pour rcuprer des donnes 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 rponse : ${reponse.status}`);
    }

    const resultat = await reponse.json();
    console.log(resultat);
  } catch (erreur) {
    console.error(erreur.message);
  }
}

Nous dclarons une chane de caractres contenant l'URL puis appelons fetch(), en passant l'URL sans options supplmentaires.

La fonction fetch() rejettera la promesse en cas de certaines erreurs, mais pas si le serveur rpond avec un statut d'erreur comme 404 : nous vrifions donc aussi le statut de la rponse et lanons une exception si ce n'est pas OK.

Sinon, nous rcuprons le contenu du corps de la rponse au format JSON en appelant la mthode json() de l'interface Response, et affichons l'une de ses valeurs. Notez que, comme fetch() elle-mme, json() est asynchrone, tout comme toutes les autres mthodes d'accs au contenu du corps de la rponse.

Dans la suite de cette page, nous examinerons plus en dtail les diffrentes tapes de ce processus.

Dans cet article

Effectuer une requte

Pour effectuer une requte, appelez fetch() en passant :

  1. une dfinition de la ressource rcuprer. Cela peut tre :
  2. ventuellement, un objet contenant des options pour configurer la requte.

Dans cette section, nous allons regarder certaines des options les plus couramment utilises. Pour lire toutes les options qui peuvent tre donnes, voir la page de rfrence de la mthode fetch().

Dfinir la mthode

Par dfaut, fetch() effectue une requte GET, mais vous pouvez utiliser l'option method pour utiliser une mthode de requte diffrente :

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

Si l'option mode est dfinie sur no-cors, alors method doit tre l'une des valeurs GET, POST ou HEAD.

Dfinir un corps de requte

Le corps de la requte est la charge utile de la requte : c'est ce que le client envoie au serveur. Vous ne pouvez pas inclure de corps avec les requtes GET, mais c'est utile pour les requtes qui envoient du contenu au serveur, comme les requtes POST ou PUT. Par exemple, si vous souhaitez tlverser un fichier vers le serveur, vous pouvez effectuer une requte POST et inclure le fichier comme corps de la requte.

Pour dfinir un corps de requte, passez-le en option body :

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 chanes de caractres l'aide de leur mthode toString(). Par exemple, vous pouvez utiliser un objet URLSearchParams pour encoder des donnes de formulaire (voir Dfinir les en-ttes 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 rponse, les corps de requte sont des flux, et effectuer la requte lit le flux, donc si une requte 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 devrez crer un clone de la requte 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);

Voir les flux verrouills et perturbs pour plus d'informations.

Dfinir les en-ttes

Les en-ttes de requte fournissent au serveur des informations sur la requte : par exemple, dans une requte POST, l'en-tte Content-Type indique au serveur le format du corps de la requte.

Pour dfinir des en-ttes de requte, assignez-les l'option headers.

Vous pouvez passer ici un objet littral contenant des proprits nom-en-tte: valeur-en-tte :

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 objet Headers, ajouter des en-ttes cet objet avec Headers.append(), puis assigner l'objet Headers l'option headers :

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'objet Headers fournit une validation supplmentaire des entres. Par exemple, il normalise les noms d'en-tte en minuscules, supprime les espaces en dbut et fin de valeur, et empche certains en-ttes d'tre dfinis. De nombreux en-ttes sont dfinis automatiquement par le navigateur et ne peuvent pas tre dfinis par un script : ce sont les en-ttes de requte interdits. Si l'option mode est dfinie sur no-cors, l'ensemble des en-ttes autoriss est encore plus restreint.

Envoyer des donnes dans une requte GET

Les requtes GET n'ont pas de corps, mais vous pouvez tout de mme envoyer des donnes au serveur en les ajoutant l'URL sous forme de chane de requte. C'est une faon courante d'envoyer des donnes de formulaire au serveur. Vous pouvez le faire en utilisant URLSearchParams pour encoder les donnes, puis en les ajoutant l'URL :

js
const params = new URLSearchParams();
params.append("username", "exemple");

// Requte GET envoye  https://exemple.org/login?username=exemple
const reponse = await fetch(`https://exemple.org/login?${params}`);

Effectuer des requtes inter-origines

La possibilit d'effectuer une requte inter-origines est dtermine par la valeur de l'option RequestInit.mode. Cette option peut prendre l'une des trois valeurs suivantes : cors, same-origin ou no-cors.

  • Pour les requtes fetch, la valeur par dfaut de mode est cors, ce qui signifie que si la requte est inter-origines, elle utilisera le mcanisme de partage des ressources entre origines (CORS). Cela signifie :

    • si la requte est une requte simple, la requte sera toujours envoye, mais le serveur doit rpondre avec l'en-tte Access-Control-Allow-Origin appropri, sinon le navigateur ne partagera pas la rponse avec l'appelant.
    • si la requte n'est pas une requte simple, le navigateur enverra une requte de pr-vrification pour vrifier que le serveur comprend CORS et autorise la requte, et la requte relle ne sera envoye que si le serveur rpond la requte de pr-vrification avec les en-ttes CORS appropris.
  • Dfinir mode sur same-origin interdit compltement les requtes inter-origines.

  • Dfinir mode sur no-cors dsactive CORS pour les requtes inter-origines. Cela restreint les en-ttes qui peuvent tre dfinis et limite les mthodes GET, HEAD et POST. La rponse est opaque, ce qui signifie que ses en-ttes et son corps ne sont pas accessibles en JavaScript. La plupart du temps, un site web ne devrait pas utiliser no-cors : son principal usage concerne certains cas d'utilisation des service workers.

Voir la documentation de rfrence pour RequestInit.mode pour plus de dtails.

Inclure des informations d'authentification

Dans le contexte de l'API Fetch, une information d'authentification est une donne supplmentaire envoye avec la requte que le serveur peut utiliser pour authentifier l'utilisateurice. Tous les lments suivants sont considrs comme des informations d'authentification :

Par dfaut, les informations d'authentification ne sont incluses que dans les requtes de mme origine. Pour personnaliser ce comportement, ainsi que pour contrler si le navigateur respecte les en-ttes de rponse Set-Cookie, dfinissez l'option credentials, qui peut prendre l'une des trois valeurs suivantes :

  • omit : n'envoie jamais d'informations d'authentification dans la requte et n'en inclut pas dans la rponse.
  • same-origin (valeur par dfaut) : n'envoie et n'inclut les informations d'authentification que pour les requtes de mme origine.
  • include : inclut toujours les informations d'authentification, mme pour les requtes inter-origines.

Notez que si l'attribut SameSite d'un cookie est dfini sur Strict ou Lax, alors le cookie ne sera pas envoy entre sites, mme si credentials est dfini sur include.

Inclure des informations d'authentification dans des requtes inter-origines peut rendre un site vulnrable aux attaques de type CSRF. Ainsi, mme si credentials est dfini sur include, le serveur doit galement accepter leur inclusion en ajoutant l'en-tte Access-Control-Allow-Credentials dans sa rponse. De plus, dans ce cas, le serveur doit dfinir explicitement l'origine du client dans l'en-tte de rponse Access-Control-Allow-Origin (c'est--dire que * n'est pas autoris).

Cela signifie que si credentials est dfini sur include et que la requte est inter-origines :

  • Si la requte est une requte simple, alors la requte sera envoye avec les informations d'authentification, mais le serveur doit dfinir les en-ttes de rponse Access-Control-Allow-Credentials et Access-Control-Allow-Origin, sinon le navigateur retournera une erreur rseau l'appelant. Si le serveur dfinit les bons en-ttes, alors la rponse, y compris les informations d'authentification, sera transmise l'appelant.

  • Si la requte n'est pas une requte simple, alors le navigateur enverra une requte de pr-vrification sans informations d'authentification, et le serveur doit dfinir les en-ttes de rponse Access-Control-Allow-Credentials et Access-Control-Allow-Origin, sinon le navigateur retournera une erreur rseau l'appelant. Si le serveur dfinit les bons en-ttes, alors le navigateur poursuivra avec la requte relle, y compris les informations d'authentification, et transmettra la rponse relle, y compris les informations d'authentification, l'appelant.

Crer un objet Request

Le constructeur Request() prend les mmes arguments que fetch() lui-mme. Cela signifie qu'au lieu de passer des options fetch(), vous pouvez passer les mmes options au constructeur Request(), puis passer cet objet fetch().

Par exemple, on peut effectuer une requte 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 rcrire cela pour passer les mmes arguments au constructeur Request() :

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 crer une requte partir d'une autre requte, tout en modifiant certaines de ses proprits l'aide du second argument :

js
async function post(requete) {
  try {
    const reponse = await fetch(requete);
    const resultat = await reponse.json();
    console.log("Russite :", 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 requte

Pour rendre une requte annulable, crez un AbortController, et assignez son AbortSignal la proprit signal de la requte.

Pour annuler la requte, appelez la mthode abort() du contrleur. L'appel fetch() rejettera la promesse avec une exception AbortError.

js
const controleur = new AbortController();

const btnRecuperation = document.querySelector("#fetch");
btnRecuperation.addEventListener("click", async () => {
  try {
    console.log("Dbut de la rcupration");
    const reponse = await fetch("https://exemple.org/get", {
      signal: controleur.signal,
    });
    console.log(`Rponse : ${reponse.status}`);
  } catch (e) {
    console.error(`Erreur : ${e}`);
  }
});

const btnAnnuler = document.querySelector("#cancel");
btnAnnuler.addEventListener("click", () => {
  controleur.abort();
  console.log("Rcupration annule");
});

Si la requte est annule aprs que l'appel fetch() a t accompli mais avant que le corps de la rponse n'ait t lu, alors toute tentative de lecture du corps de la rponse rejettera avec une exception AbortError.

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 rponse

Ds que le navigateur a reu le statut de la rponse et les en-ttes du serveur (et potentiellement avant que le corps de la rponse lui-mme ait t reu), la promesse retourne par fetch() est tenue avec un objet Response.

Vrifier le statut de la rponse

La promesse retourne par fetch() sera rejete en cas de certaines erreurs, comme une erreur rseau ou un mauvais schma. Cependant, si le serveur rpond avec une erreur comme 404, alors fetch() est tenue avec un objet Response, il faut donc vrifier le statut avant de lire le corps de la rponse.

La proprit Response.status donne le code de statut numrique, et la proprit Response.ok retourne true si le statut est dans la plage 200.

Un schma courant consiste vrifier la valeur de ok et lancer une exception si elle vaut false :

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 rponse : ${reponse.status}`);
    }
    // 
  } catch (erreur) {
    console.error(erreur.message);
  }
}

Vrifier le type de la rponse

Les rponses possdent une proprit type qui peut avoir l'une des valeurs suivantes :

  • basic : la requte tait de mme origine.
  • cors : la requte tait une requte CORS inter-origines.
  • opaque : la requte tait une requte simple inter-origines effectue avec le mode no-cors.
  • opaqueredirect : la requte a dfini l'option redirect sur manual, et le serveur a retourn un statut de redirection.

Le type dtermine le contenu possible de la rponse, comme suit :

  • Les rponses de type basic excluent les en-ttes de rponse de la liste de nom d'en-tte de rponse interdit.

  • Les rponses CORS incluent uniquement les en-ttes de rponse de la liste de en-tte de rponse autoris par CORS.

  • Les rponses opaques et les rponses opaques de redirection ont un status de 0, une liste d'en-ttes vide et un corps null.

Vrifier les en-ttes

Comme pour la requte, la rponse possde une proprit headers qui est un objet Headers, et celui-ci contient tous les en-ttes de rponse exposs aux scripts, sous rserve des exclusions selon le type de rponse.

Un cas d'usage courant consiste vrifier 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 rponse

L'interface Response fournit plusieurs mthodes pour rcuprer l'intgralit du contenu du corps dans diffrents formats :

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

Dans cet exemple, on rcupre une image et on la lit comme un Blob, que l'on peut ensuite utiliser pour crer 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 rponse : ${reponse.status}`);
    }
    const blob = await reponse.blob();
    const urlObjet = URL.createObjectURL(blob);
    image.src = urlObjet;
  } catch (e) {
    console.error(e);
  }
}

La mthode lancera une exception si le corps de la rponse n'est pas dans le format appropri : par exemple, si vous appelez json() sur une rponse qui ne peut pas tre analyse comme JSON.

Lire le corps de la rponse en flux

Les corps de requte et de rponse sont en ralit des objets ReadableStream, et chaque fois que vous les lisez, vous traitez le contenu en flux. Cela est avantageux pour la gestion de la mmoire, car le navigateur n'a pas besoin de mettre en mmoire tampon toute la rponse avant que l'appelant la rcupre avec une mthode comme json().

Cela signifie aussi que l'appelant peut traiter le contenu de faon incrmentale au fur et mesure qu'il est reu.

Par exemple, considrez une requte GET qui rcupre un grand fichier texte et le traite d'une certaine manire, ou l'affiche l'utilisateurice :

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 rponse : ${reponse.status}`);
    }

    const texte = await reponse.text();
    console.log(texte);
  } catch (e) {
    console.error(e);
  }
}

Si on utilise Response.text(), comme ci-dessus, il faut attendre que tout le fichier soit reu avant de pouvoir en traiter une partie.

Si on lit la rponse en flux, on peut traiter des morceaux du corps au fur et mesure qu'ils sont reus du rseau :

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 rponse : ${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, on itre de faon asynchrone sur le flux, en traitant chaque morceau mesure qu'il arrive.

Notez que lorsque vous accdez directement au corps de cette faon, vous obtenez les octets bruts de la rponse et devez les transformer vous-mme. Ici, on appelle ReadableStream.pipeThrough() pour faire passer la rponse dans un TextDecoderStream, qui dcode les donnes du corps encodes en UTF-8 en texte.

Traiter un fichier texte ligne par ligne

Dans l'exemple ci-dessous, on rcupre une ressource texte et on la traite ligne par ligne, en utilisant une expression rgulire pour dtecter les fins de ligne. Par simplicit, on suppose que le texte est en UTF-8 et on ne gre pas les erreurs de rcupration :

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 dernire ligne ne se termine pas par un caractre 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 verrouills et perturbs

Les consquences du fait que les corps de requte et de rponse sont des flux sont les suivantes :

  • si un lecteur a t attach un flux avec ReadableStream.getReader(), alors le flux est verrouill, et rien d'autre ne peut lire le flux.
  • si du contenu a t lu depuis le flux, alors le flux est perturb, et rien d'autre ne peut lire depuis le flux.

Cela signifie qu'il n'est pas possible de lire le mme corps de rponse (ou de requte) 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 rponse : ${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 appeler Response.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 rponse : ${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 schma courant lors de la mise en uvre d'un cache hors ligne avec les service workers. Le service worker souhaite retourner la rponse l'application, mais aussi mettre la rponse en cache. Il clone donc la rponse, 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


Web Proxy Viewer  |  New URL  |  Original Page