13 novembre 2022

API Fetch

Jusqu’à présent, nous en savons pas mal sur fetch.

Voyons le reste de l’API, pour couvrir toutes ses capacités.

Veuillez noter :

Remarque: la plupart de ces options sont rarement utilisées. Vous pouvez ignorer ce chapitre et continuer à utiliser fetch correctement.

Pourtant, il est bon de savoir ce que fetch peut faire, donc si le besoin s’en fait sentir, vous pouvez revenir et lire les détails.

Voici la liste complète de toutes les options possibles de fetch avec leurs valeurs par défaut (alternatives dans les commentaires) :

let promise = fetch(url, {
  method: "GET", // POST, PUT, DELETE, etc.
  headers: {
    // la valeur de l'en-tête du type de contenu est généralement définie automatiquement
    // selon la requête du body
    "Content-Type": "text/plain;charset=UTF-8"
  },
  body: undefined, // string, FormData, Blob, BufferSource, ou URLSearchParams
  referrer: "about:client", // ou "" to send no Referer header,
  // or an url from the current origin
  referrerPolicy: "strict-origin-when-cross-origin", // no-referrer-when-downgrade, no-referrer, origin, same-origin...
  mode: "cors", // same-origin, no-cors
  credentials: "same-origin", // omit, include
  cache: "default", // no-store, reload, no-cache, force-cache, or only-if-cached
  redirect: "follow", // manual, error
  integrity: "", // un hash, comme "sha256-abcdef1234567890"
  keepalive: false, // true
  signal: undefined, // AbortController pour annuler la requête
  window: window // null
});

Une liste impressionnante, non ?

Nous avons entièrement couvert method, headers et body dans le chapitre Fetch.

L’option signal est couverte dans Fetch: Abort.

Explorons maintenant le reste des capacités.

referrer, referrerPolicy

Ces options régissent la façon dont fetch définit l’en-tête HTTP Referer.

Habituellement, cet en-tête est défini automatiquement et contient l’url de la page à l’origine de la requête. Dans la plupart des scénarios, ce n’est pas important du tout, parfois, pour des raisons de sécurité, il est logique de le supprimer ou de le raccourcir.

L’option referer permet de définir n’importe quel Referer dans l’origine actuelle) ou de le supprimer.

Pour n’envoyer aucun referer, définissez une chaîne de caractères vide :

fetch('/page', {
  referrer: "" // pas de header Referer
});

Pour définir une autre URL dans l’origine actuelle :

fetch('/page', {
  // en supposant que nous sommes sur https://javascript.info
  // nous pouvons définir n'importe quel en-tête Referer, mais uniquement dans l'origine actuelle
  referrer: "https://javascript.info/anotherpage"
});

L’option referrerPolicy établit des règles générales pour Referer.

Les requêtes sont divisées en 3 types :

  1. Requête à la même origine.
  2. Requête à une autre origine.
  3. Requête de HTTPS à HTTP (du protocole sûr au protocole non sécurisé).

Contrairement à l’option referrer qui permet de définir la valeur exacte de Referer, referrerPolicy indique les règles générales du navigateur pour chaque type de requête.

Les valeurs possibles sont décrites dans la spécification Referrer Policy:

  • "strict-origin-when-cross-origin" – la valeur par défaut : pour la même origine, envoie le Referer complet, pour l’origine croisée, envoie uniquement l’origine, à moins qu’il ne s’agisse d’une requête HTTPS→HTTP , puis n’envoie rien.
  • "no-referrer-when-downgrade" – le Referer complet est toujours envoyé, sauf si nous envoyons une requête de HTTPS à HTTP (vers le protocole le moins sécurisé).
  • "no-referrer" – n’envoie jamais le Referer.
  • "origine" – n’envoie que l’origine dans le Referer, pas l’URL complète de la page, par ex. uniquement http://site.com au lieu de http://site.com/path.
  • "origin-when-cross-origin" – envoie le Referer complet à la même origine, mais uniquement la partie d’origine pour les requêtes cross-origin (comme ci-dessus).
  • "same-origin" – envoie le Referer complet à la même origine, mais pas de Referer pour les requêtes cross-origin.
  • "strict-origin" – envoie uniquement l’origine, pas le Referer pour les requêtes HTTPS→HTTP.
  • "unsafe-url" – envoie toujours l’url complète dans Referer, même pour les requêtes HTTPS→HTTP.

Voici un tableau avec toutes les combinaisons :

Valeur Pour la même origine Pour une autre origine HTTPS→HTTP
"no-referrer" - - -
"no-referrer-when-downgrade" full full -
"origin" origin origin origin
"origin-when-cross-origin" full origin origin
"same-origin" full - -
"strict-origin" origin origin -
"strict-origin-when-cross-origin" or "" (default) full origin -
"unsafe-url" full full full

Disons que nous avons une zone d’administration avec une structure d’URL qui ne devrait pas être connue de l’extérieur du site.

Si nous envoyons un fetch, alors par défaut, il envoie toujours l’en-tête Referer avec l’url complète de notre page (sauf lorsque nous demandons de HTTPS à HTTP, alors pas de Referer).

Par exemple : Referer: https://javascript.info/admin/secret/paths.

Si nous souhaitons que d’autres sites Web connaissent uniquement la partie origin, pas le chemin URL, nous pouvons définir l’option :

fetch('https://another.com/page', {
  // ...
  referrerPolicy: "origin-when-cross-origin" // Referer: https://javascript.info
});

Nous pouvons le mettre à tous les appels fetch, peut-être l’intégrer dans la bibliothèque JavaScript de notre projet qui fait toutes les requêtes et utilise fetch à l’intérieur.

Sa seule différence par rapport au comportement par défaut est que pour les requêtes vers une autre origine, fetch envoie uniquement la partie origine de l’URL (par exemple https://javascript.info, sans le chemin). Pour les requêtes à notre origine, nous obtenons toujours le Referer complet (peut-être utile à des fins de débogage).

La Referrer policy n’est pas seulement pour fetch

La Referrer policy, décrite dans la spécification, n’est pas seulement pour fetch, mais plus globale.

Plus particulièrement, il est possible de définir la politique par défaut pour toute la page en utilisant l’en-tête HTTP Referrer-Policy, ou par lien, avec <a rel="noreferrer">.

mode

L’option mode est un garde-fou qui empêche les requêtes cross-origin occasionnelles :

  • "cors" – par défaut, les requêtes cross-origin sont autorisées, comme décrit dans Fetch: Requêtes Cross-Origin,
  • "same-origin" – les requêtes cross-origin requests sont interdites,
  • "no-cors" – seules les requêtes cross-origin sécurisées sont autorisées.

Cette option peut être utile lorsque l’URL de fetch provient d’un tiers, et nous voulons un “interrupteur de mise hors tension” pour limiter les capacités de cross-origin.

credentials

L’option credentials spécifie si fetch doit envoyer des cookies et des en-têtes d’autorisation HTTP avec la requête.

  • "same-origin" – par défaut, n’envoyez pas de requêtes cross-origin,
  • "include" – toujours envoyer, nécessite Accept-Control-Allow-Credentials du serveur cross-origin pour que JavaScript accède à la réponse, qui a été traitée dans le chapitre Fetch: Requêtes Cross-Origin,
  • "omit" – ne jamais envoyer, même pour des requêtes cross-origin.

cache

Par défaut, les requêtes fetch utilisent la mise en cache HTTP standard. Autrement dit, il honore les en-têtes Expires et Cache-Control, envoie If-Modified-Since, et ainsi de suite. Tout comme les requêtes HTTP régulières.

Les options cache permettent d’ignorer le cache HTTP ou d’affiner son utilisation :

  • "default"fetch utilise des règles et des en-têtes de cache HTTP standard,
  • "no-store" – ignore totalement le cache HTTP, ce mode devient la valeur par défaut si nous définissons un en-tête If-Modified-Since, If-None-Match, If-Unmodified-Since, If-Match, ou If-Range,
  • "reload" – ne prenez pas le résultat du cache HTTP (le cas échéant), mais remplissez le cache avec la réponse (si les en-têtes de réponse le permettent),
  • "no-cache" – créer une requête conditionnelle s’il y a une réponse mise en cache, et sinon une requête normale. Remplissez le cache HTTP avec la réponse,
  • "force-cache" – utilise une réponse du cache HTTP, même si elle est périmée. S’il n’y a pas de réponse dans le cache HTTP, fait une requête HTTP régulière, se comporte normalement,
  • "only-if-cached" – utilise une réponse du cache HTTP, même si elle est périmée. S’il n’y a pas de réponse dans le cache HTTP, alors erreur. Fonctionne uniquement lorsque le mode est sur "same-origin".

redirect

Normalement, fetch suit de manière transparente les redirections HTTP, comme 301, 302 etc.

L’option redirect permet de changer cela :

  • "follow" – par défaut, suit les redirections HTTP,
  • "error" – erreur en cas de redirection HTTP,
  • "manual" – permet de traiter manuellement les redirections HTTP. En cas de redirection, nous obtiendrons un objet de réponse spécial, avec response.hype="opaqueredirect" et un statut zéro/vide ainsi que la plupart des autres propriétés.

integrity

L’option intégrité permet de vérifier si la réponse correspond à la somme de contrôle connue à l’avance.

Comme décrit dans la spécification, les fonctions de hachage prises en charge sont SHA-256, SHA-384 et SHA-512, il peut y en avoir d’autres en fonction du navigateur.

Par exemple, nous téléchargeons un fichier et nous savons que sa somme de contrôle SHA-256 est “abcdef” (une vraie somme de contrôle est plus longue, bien sûr).

Nous pouvons le mettre dans l’option integrity, comme ceci :

fetch('http://site.com/file', {
  integrity: 'sha256-abcdef'
});

Ensuite, fetch calculera SHA-256 seul et le comparera avec notre chaîne de caractères. En cas de non-concordance, une erreur est déclenchée.

keepalive

L’option keepalive indique que la demande peut “survivre” à la page Web qui l’a initiée.

Par exemple, nous recueillons des statistiques sur la façon dont le visiteur actuel utilise notre page (clics de souris, fragments de page qu’il consulte), pour analyser et améliorer l’expérience utilisateur.

Lorsque le visiteur quitte notre page – nous aimerions enregistrer les données sur notre serveur.

Nous pouvons utiliser l’événement window.onunload pour cela :

window.onunload = function() {
  fetch('/analytics', {
    method: 'POST',
    body: "statistics",
    keepalive: true
  });
};

Normalement, lorsqu’un document est déchargé, toutes les requêtes réseau associées sont abandonnées. Mais l’option keepalive indique au navigateur d’exécuter la requête en arrière-plan, même après avoir quitté la page. Cette option est donc essentielle à la réussite de notre demande.

Elle a quelques limitations :

  • Nous ne pouvons pas envoyer des mégaoctets : la limite de corps pour les requêtes keepalive est de 64kb.
    • Si nous avons besoin de rassembler beaucoup de statistiques sur la visite, nous devons les envoyer régulièrement par paquets, afin qu’il ne reste plus grand-chose pour la dernière requête onunload.
    • Cette limite s’applique à toutes les demandes keepalive ensemble. En d’autres termes, nous pouvons effectuer plusieurs requêtes keepalive en parallèle, mais la somme de leurs longueurs de corps ne doit pas dépasser 64 Kb.
  • Nous ne pouvons pas gérer la réponse du serveur si le document est déchargé. Donc, dans notre exemple, fetch réussira grâce à keepalive, mais les fonctions suivantes ne fonctionneront pas.
    • Dans la plupart des cas, comme l’envoi de statistiques, ce n’est pas un problème, car le serveur accepte simplement les données et envoie généralement une réponse vide à de telles demandes.
Carte du tutoriel

Commentaires

lire ceci avant de commenter…
  • Si vous avez des améliorations à suggérer, merci de soumettre une issue GitHub ou une pull request au lieu de commenter.
  • Si vous ne comprenez pas quelque chose dans l'article, merci de préciser.
  • Pour insérer quelques bouts de code, utilisez la balise <code>, pour plusieurs lignes – enveloppez-les avec la balise <pre>, pour plus de 10 lignes - utilisez une sandbox (plnkr, jsbin, codepen…)