--- title: 'HTTP : Requêtes conditionnelles' slug: Web/HTTP/Conditional_requests tags: - Guide - HTTP - Requêtes Conditionnelles translation_of: Web/HTTP/Conditional_requests original_slug: Web/HTTP/Requêtes_conditionnelles ---
{{HTTPSidebar}}
HTTP a un concept de requête conditionnelle où le résultat, et même le succés d'une requête, peut être changé en comparant les ressources affectées avec la valeur d'un validateur. De telles requêtes peuvent être utiles pour valider le contenu d'un cache et mettre de côté un contrôle inutile pour vérifier l'intégrité d'un document, comme le sommaire d'un téléchargement, ou éviter de perdre des mises à jour quand on télécharge ou modifie un document sur le serveur.
Les requêtes conditionnelles HTTP s'exécutent différemment en fonction de la valeur spécifique des en-têtes. Ces en-têtes définissent une condition de départ (pré-condition) et le résultat de la requête sera différent selon que la pré-condition est satisfaite ou non.
Les comportements différents sont définis par la méthode qu'utilise la requête et par un ensemble d'en-têtes propres aux préconditions :
Toutes les en-têtes conditionnelles vérifient si la ressource stockée sur le serveur correspond à une version spécifique. Pour accomplir ceci, la requête conditionnelle doit préciser la version de la ressource car comparer l'ensemble bit à bit n'est pas faisable et pas toujours désiré non plus. La requête transmet une valeur qui caractérise la version. Ces valeurs sont appelées validateurs et il y en a de deux sortes :
Comparer les versions d'une même ressource est un peu délicat : en fonction du contexte, il y a deux sortes de vérification d'équivalence :
La sorte de la vérification est indépendante du validateur utilisé. {{HTTPHeader("Last-Modified")}} et {{HTTPHeader("ETag")}} permettent les deux tupes de validation bien que la complexité d'implémentation côté serveur soit variable. HTTP se sert de la validation forte par défaut et spécifie quand la validation faible peut être employée.
La validation forte consiste à garantir que la ressource est identique à celle à laquelle elle est comparée, au bit prés. C'est obligatoire pour certaines en-têtes et le défaut pour les autres. La validation forte est stricte et peut être difficile à garantir côté serveur mais cela garantit qu'à aucun moment une donnée n'est perdu, parfois au détriment de la performance.
Il est assez difficile d'avoir un identifiant unique pour la validation forte avec {{HTTPHeader("Last-Modified")}}. On le fait souvent en employant une {{HTTPHeader("ETag")}} avec le hachage MD5 de la ressource(ou un dérivé).
La validation faible différe de la validation forte car elle considère que deux versions du document ayant le même contenu sont équivalentes. Par exemple, une page qui différerait d'une autre seulement par sa date dans le pied de page ou une publicité, sera considérée identique à l'autre avec la validation faible. Ces mêmes deux versions seront évaluées comme étant différentes avec la validation forte. Construire un système d'ETags pour la validation faible peut être complexe car cela induit de connaître l'importance des différents éléments de la page mais est trés utile dans le but d'optimiser les performances du cache.
Plusieurs en-têtes HTTP, appelées en-têtes conditionelles, apportent des conditions aux reques. Ce sont :
'W/'
, c'est une validation forte. it performs a strong validation.'W/'
, c'est une validation forte.Partial Content
, un {{HTTPStatus("200")}} OK
est envoyé avec la totlité de la ressource.Le cas d'utilisation le plus commun pour les requêtes conditionnelles est la mise à jour du cache. Avec un cache vide ou absent, la ressource demandée est renvoyée avec un statut {{HTTPStatus("200")}} OK
.
Dans la ressource les validateurs sont renvoyés dans les en-têtes. Dans cet exemple, deux validateurs {{HTTPHeader("Last-Modified")}} et {{HTTPHeader("ETag")}} sont envoyés mais il pourrait tout aussi bien n'y en avoir qu'un. Ces validateurs sont en cache avec la ressource (comme toutes les en-têtes) et seront utilisés pour embarquer les requêtes conditionnelles quand le cache est périmé.
Tant que le cache n'est pas obsolète, aucune requête n'esst publiée. Mais une fois qu'il est dépassé, il est principalement contrôlé par l'en-tête {{HTTPHeader("Cache-Control")}} , le client n'utilise pas directement la valeur en cache mais publie une requête conditionnelle. La valeur du validateur est employé comme paramètre des en-têtes {{HTTPHeader("If-Modified-Since")}} et {{HTTPHeader("If-Match")}}.
Si la ressource n'a pas changé, le serveur renvoie une réponse {{HTTPStatus("304")}} Not Modified
. Cela rafraîchit le cache et le client peut se servir de la valeur en cache. Bien qu'il y ait un aller-retour requête-réponse qui consomme quelques ressources, cette méthode est plus efficace que de transmettre à nouveau la totalité de la ressource via le réseau.
Si la ressource n'a pas changée, le serveur renvoie juste une réponse {{HTTPStatus("200")}} OK
avec la nouvelle version de la ressource comme si la requête n'était pas conditionnelle et le client utilise cette nouvelle ressource et la met en cache.
De plus, la configuration des validateurs côté serveur est totalement transparente : tous les navigateurs gèrent un cache et envoient de telles requêtes conditionnelles sans que cela ne nécessite de travail supplémentaire de la part du développeur.
Un téléchargement partiel de fichiers est une fonctionnalité de HTTP qui permet de reprendre des opérations en cours en économisant de la bande passante et du temps en conservant les données déjà reçues :
Un serveur qui supporte le téléchargement partiel le diffuse en envoyant une en-tête {{HTTPHeader("Accept-Ranges")}}. Quand il la reçoit, le client peut reprendre le téléchargement en envoyant une en-tête de requête {{HTTPHeader("Ranges")}} avec les données manquantes :
Le principe est simple mais il y a un problème potentiel : si la ressource téléchargée a été modifiée entre deux téléchargements, les données reçues correspondront à deux versions différentes de la ressource et le fichier final sera corrompu. Pour prévenir cela, des en-têtes conditionnelles sont employées. Il y a deux manières de faire : la plus flexible se sert de {{HTTPHeader("If-Modified-Since")}} et de {{HTTPHeader("If-Match")}}, le serveur retourne alors une erreur si la "pré-condition" n'est pas satisfaite et le client reprend le téléchargement depuis le début :
Même si cette méthode marche, elle ajoute un échange requête/réponse quand le document a été modifié. Cela impacte la performance et HTTP a prévu une en-tête spécifique pour éviter ce scénario : {{HTTPHeader("If-Range")}}:
Cette solution est plus efficace mais légèrement moins flexible puisqu' une etag seulement peut être utilisée dans la condition. On a rarement besoin d'une telle flexibilité additionnelle.
Une opération commune des applications web est la mise à jour de document distants. C'est trés usuel dans tout système de fichiers ou dans les applications de contrôle de source et toute application qui permet de stocker des ressources distantes a besoin de ce mécanisme. Les sites comme les wikis et autres CMS s'en servent habituellement.
Vous pouvez l'implémenter avec la méthode {{HTTPMethod("PUT")}}. Le client lit d'abord les fichiers originaux, les modifie et finalement, les envoie au serveur.
Cependant, les choses deviennent un peu moins précises dés que l'on parle de simultanéité des comptes. Pendant qu'un client est en train de modifier localement sa nouvelle copie de la ressource, un second client peut récupérer la même ressource et faire de même avec sa copie. Ce qui arrive ensuite est regrettable : quand ils enregistrent les modifications sur le serveur, celles du premier client sont écartées par l'enregistrement du second client qui n'est pas au courant des changements effectués sur la ressource par le premier client. Le choix qui est fait n'est pas communiqué aux autres protagonistes. Les changements adoptés changeront avec la vitesse d'enregistrement, ce qui dépend de la performance des clients, des serveurs et même de l'humain qui édite le document sur le client. Le "gagnant" changera d'une fois à l'autre. C'est donc une "course des conditions" ({{glossary("race condition")}}) qui conduit à des comportements problématiques difficiles à cerner et à débugger.
Il n'existe aucune manière de gérer ce problème sans ennuyer l'un ou l'autre client. De toutes façons, les mises à jour perdues et la "course des conditions" sont appelées à disparaître. Nous voulons des résultats prévisibles et être notifiés quand les changements sont rejetés.
Les requêtes conditionnelles permettent d'implémenter l'algorithme de contrôle de concurrence (optimistic locking algorithm) utilisé par la plupart des wikis ou systèmes de contrôle des sources. Le concept est de permettre au client d'avoir des copies de la ressource, les laisser se modifier localement puis de contrôler la mise en concurrence en autorisant celles du premier client soumettant une mise à jour. Toutes les mises à jour ultèrieures basées sur la version maintenant obsolète sont rejetées :
Ce ci est implémenté par les en-têtes {{HTTPHeader("If-Match")}} ou {{HTTPHeader("If-Unmodified-Since")}} . Si l'etag ne correspond pas au fichier original ou si le fichier a été modifié depuis son obtention, le changement est alors simplement rejeté avec une erreur {{HTTPStatus("412")}} Precondition Failed
. C'est maintenant à l'initiative du client que se réglera l'erreur : soit en prévenant le client de redémarrer avec la nouvelle version, soit en présentant au client les différences entre les deux versions pour l'aider à choisir les modifications à conserver.
Le premier téléchargement d'une ressource est un des cas résultant du comportement précédent. Comme toute mise à jour d'une ressource, le téléchargement va faire l'objet d'une "course des conditions" si deux clients essaient un enregistrement au même instant. Pour éviter cela, les en-têtes conditionnelles peuvent être employées : on ajoute {{HTTPHeader("If-None-Match")}} avec la valeur particulière '*'
, représentant n'importe quelle etag. La requête aboutira seulement si la ressource n'existait pas avant :
If-None-Match
fonctionnera seulement avec les serveurs compatibles HTTP/1.1 (et postérieur). Si vous n'êtes pas sûr que le serveur le soit, vous devez d'abord envoyer une requête {{HTTPMethod("HEAD")}} à la ressource pour vérifier.
Les requêtes conditionnelles sont une fonctionnalité essentielle d'HTTP et permettent la construction d'applications efficaces et complexes. Pour le cache et la reprise des téléchargements, la seule obligation du webmaster est de configurer le serveur correctement, en paramètrant les bonnes etags : dans certains environnements, c'est un véritable défi. Une fois cela fait, le serveur renverra les requêtes conditionnelles adaptées.
Pour verrouiller ces dispositifs, c'est l'inverse : les développeurs web devront publier une requête avec les en-têtes appropriées tandis que les webmasters peuvent en général se fier à l'application pour effectuer ces vérifications.
Dans les deux cas, c'est clair, les requêtes conditionnelles sont une des fonctionnalités essentielles du Web.