Les requêtes conditionnelles HTTP

Les requêtes conditionnelles sont des requêtes HTTP qui incluent un ou plusieurs champs d’en-tête indiquant une condition préalable à tester avant d’appliquer la méthode à la ressource cible.

 

A quoi servent les requêtes HTTP conditionnelles

Concrètement, les requêtes conditionnelles vont pouvoir être utiles dans deux situations différentes :

  • Pour valider un cache HTTP efficacement dans le cas d’une requête GET ;
  • Pour éviter les problèmes d’écrasement et donc de perte de mise à jour dans le cas où deux clients modifieraient la même ressource en même temps avec une requête PUT ou DELETE par exemple.

 

Comment fonctionne une requête conditionnelle ?

Les requêtes conditionnelles sont des requêtes où le résultat va pouvoir être différent en fonction de la valeur d’un validateur.

Les validateurs vont prendre la forme d’en-têtes qu’on appelle des en-têtes conditionnelles. Ces en-têtes vont nous permettre de définir une condition de départ et cette condition va justement conditionner le résultat de la requête (selon que la condition soit validée ou pas).

Dans le cas d’une requête GET, par exemple, on va pouvoir utiliser des requêtes conditionnelles pour faire en sorte que le serveur ne renvoie la ressource demandée que si elle a été modifiée ou un code 304 dans le cas contraire et ainsi économiser des ressources.

Dans le cas d’une requête modifiant les informations sur serveur, on va pouvoir utiliser les requêtes conditionnelles pour vérifier si la ressource en question n’a pas déjà été modifiée entre temps par un autre client et, dans le cas où celle-ci a bien été modifiée, refuser les nouvelles modifications (et donc empêcher un écrasement des modifications précédentes).

 

Les types de validateurs : validateurs faibles et forts

On utilise les validateurs pour vérifier (« valider ») si la ressource stockée sur le serveur correspond à sa représentation spécifique dont on dispose.

On classe les validateurs en deux catégories : les validateurs dits « faibles » et les validateurs dit « forts ».

Les validateurs forts permettent d’effectuer une comparaison (vérification) bit par bit entre la représentation de la ressource dont on dispose et sa représentation sur serveur.

Les validateurs faibles sont plus laxistes : ils vont également comparer les représentation d’une ressource mais vont les déclarer égales même si il existe des différences minimes entre elles.

Les validateurs faibles sont faciles à générer mais sont beaucoup moins utiles pour les comparaisons. Les validateurs forts sont idéaux pour les comparaisons mais peuvent être très difficiles (et parfois impossibles) à générer efficacement.

Comme il sera parfois plus pertinent d’utiliser un validateur plutôt qu’un autre, HTTP n’impose pas que toutes les formes de ressources adhèrent à la même force de validateur mais HTTP expose le type de validateur utilisé et impose des restrictions lorsque des validateurs faibles peuvent être utilisés comme conditions préalables.

 

Les en-têtes Last-Modified et ETag

On va pouvoir créer des validateurs à des valeurs des en-têtes Last-Modified et ETag. Notez déjà que ces deux en-têtes permettent en théorie chacun d’implémenter des validations faibles ou fortes mais que la complexité d’implémentation va être plus ou moins grande en pratique.

Le champ d’en-tête de réponse Last-Modified contient la date et l’heure auxquelles le serveur d’origine pense que la ressource a été modifiée pour la dernière fois.

On va l’utiliser comme validateur pour déterminer si une ressource reçue ou stockée est la même. Cet en-tête est moins précis qu’un en-tête Etag.

Par défaut, la date fournie par Last-Modified, lorsqu’elle est utilisée comme validateur dans une requête est implicitement faible sauf s’il est possible de déduire qu’elle est forte.

Les demandes conditionnelles contenant des en-têtes If-Modified-Since ou If-Unmodified-Since utilisent le champ d’en-tête Last-Modified.

Le champ d’en-tête ETag dans une réponse est un identifiant pour une version spécifique d’une ressource. Si la ressource à une URL donnée change, une nouvelle valeur ETag doit être générée.

Les valeurs des etags sont uniques et l’en-tête ETag est donc utilisé comme validateur fort par défaut.

 

Autres champs d’en-tête conditionnels

Les champs d’en-tête suivants permettent de créer des requêtes conditionnelles :

If-Match
Pour les méthodes GET et HEAD, le serveur renverra la ressource demandée uniquement si elle correspond à l’un des ETags répertoriés. Pour les méthodes non sûres, il ne téléchargera la ressource que dans ce cas.
If-None-Match
Pour les méthodes GET et HEAD, le serveur renverra la ressource demandée avec un code 200 uniquement s’il n’a pas d’ETag correspondant à ceux fournis. Pour les autres méthodes, la demande sera traitée uniquement si l’ETag de la ressource éventuellement existante ne correspond à aucune des valeurs répertoriées.
If-Modified-Since
Le serveur renverra la ressource demandée, avec un code 200, uniquement si elle a été modifiée pour la dernière fois après la date indiquée. Si la demande n’a pas été modifiée depuis, la réponse sera un 304 sans aucun corps. Cet en-tête ne peut être utilisé qu’avec une méthode GET ou HEAD.
If-Unmodified-Since
Le serveur renverra la ressource demandé, ou l’acceptera dans le cas d’une méthode non sûre uniquement si elle n’a pas été modifiée pour la dernière fois après la date indiquée. Si la ressource a été modifiée après la date indiquée, la réponse sera une erreur 412 (échec de la condition préalable). Avec des méthodes non sûres, comme POST, cet en-tête peut être utilisé pour rejeter une édition si le document stocké a été modifié depuis que l’original a été récupéré. Avec une demande de plage et un en-tête If-Range, cet en-tête peut être utilisé pour garantir que le nouveau fragment demandé provient d’un document non modifié.
If-Range
Si la condition est remplie, la demande de plage sera émise et le serveur renvoie une réponse 206 (Partial Content)avec le corps approprié. Si la condition n’est pas remplie, la ressource complète est renvoyée, avec un code de statut 200.