Services Web - EPSI POE mars 2017 - David Gayerie Licence Creative Commons

L'Hypertext Transfer Protocol (HTTP) est un protocole de la couche application. Il est le fondement de l'échange de données pour le World Wide Web. Comme tous les protocoles applicatifs d'Internet, HTTP est orienté texte.

HTTP version 1.1 est défini par un ensemble de RFC (Requests For Comments) maintenu par un groupe de travail de l'IETF (Internet Engineering Task Force) :

Structure des messages

HTTP est un protocole sans état conversationnel dans un environnement client/serveur. Le client émet une requête qui contient les informations suffisantes pour permettre au serveur de fournir une réponse.

Une requête HTTP GET
GET /Programmes/Panorama-des-etudes HTTP/1.1
Host: www.epsi.fr
				
La réponse du serveur
HTTP/1.1 200 OK
Content-Type: text/html; charset=utf-8
Content-Length: 420

<html>
...
</html>

Une requête HTTP débute par une ligne de requête (request line) terminée par un saut de ligne (CRLF). Cette ligne contient la méthode HTTP que le client souhaite exécuter, le chemin de la ressource cible sur laquelle la méthode doit s'appliquer et enfin la version du protocole HTTP utilisée (HTTP/1.1).

On trouve ensuite une liste d'en-têtes et une ligne vide qui marque la fin des en-têtes. Si la requête a un contenu (un corps de message), il est ensuite transmis.

Structure d'une requête HTTP
[méthode] [ressource cible] HTTP/1.1
[Nom de l'en-tête]: [Valeur de l'en-tête]
...
[ligne vide]
[corps de message]

Lorsque le serveur reçoit la requête, il reconstitue l'URI de la requête afin de déterminer quelle réponse il doit retourner au client. L'URI de la requête est déterminée à partir de la ressource cible et de la valeur de l'en-tête Host. Ainsi pour la requête suivante :

GET /Programmes/Panorama-des-etudes HTTP/1.1
Host: www.epsi.fr
				

Le serveur infère que le client veut exécuter la méthode GET sur l'URI :

http://www.epsi.fr/Programmes/Panorama-des-etudes

Une réponse HTTP débute par une ligne de réponse (response line) terminée par un saut de ligne (CRLF). Celle-ci donne la version du protocole de réponse, le code de statut du traitement de la requête et enfin un message décrivant le code statut. On trouve ensuite une liste d'en-têtes et une ligne vide qui marque la fin des en-têtes. Si la réponse a un contenu (un corps de message), il est ensuite transmis.

Structure d'une réponse HTTP
HTTP/1.1 [code statut] [message]
[Nom de l'en-tête]: [Valeur de l'en-tête]
...
[ligne vide]
[corps de message]

Exercice : écrivons en HTTP

Afficher le contenu de la page Web http://www.epsi.fr/Programmes/Panorama-des-etudes ... avec telnet ! Pour rappel, le protocole HTTP est associé au port 80.

Essayez ensuite avec l'URI http://www.google.com. Quelle est la différence dans la réponse du serveur ?

Exercice : introduction à cURL

cURL est un outil en ligne de commande permettant de récupérer des données à partir d'une URL. Il supporte de nombreux protocoles dont HTTP. Vous le téléchargez à partir du site officiel.

Utilisation simple de cURL
curl http://www.epsi.fr

cURL offre de nombreuses options. Celles qui vont nous être utiles :

-i
Affiche le contenu complet de la réponse HTTP. On visualise ainsi la ligne de statut et les en-têtes retournés par le serveur.
-v
Mode verbeux affichant notamment la requête émise et la réponse reçue.
-X [méthode]
Permet de préciser la méthode HTTP à utiliser dans la requête (GET par défaut).
-H "[en-tête]"
Permet d'ajouter ou de modifier un en-tête de la requête.
--data-binary [data]
Ajoute les données spécifiées comme corps du message
-o [nom de fichier]
Permet de sauvegarder la réponse retournée par le serveur dans un fichier.
Utilisation avancée de cURL
curl -v -X GET -H "Accept: text/html" http://www.epsi.fr -o /dev/null

L'exemple ci-dessus permet d'obtenir une exécution en mode verbeux d'une requête GET pour l'hote www.epsi.fr pour la ressource / en ajoutant l'en-tête Accept avec la valeur text/html. Le corps de la réponse est sauvegardé dans /dev/null, c'est-à-dire nulle part, afin que le terminal n'affiche que la ligne de statut et les en-têtes de la réponse.

Utilisation avancée de cURL
curl -v -X POST -H "Content-type: application/json"
     --data-binary '{"cours": "Web Service", "promo": "I4"}' http://api.epsi.fr/cours

L'exemple ci-dessus permet d'exécuter une méthode POST sur une API Web hypothétique en envoyant un document JSON. cURL calculera automatiquement pour nous la taille du message à envoyer. Il n'est donc pas nécessaire de préciser l'en-tête Content-length.


Reprenez les URL de l'exercice précédent pour vous familiariser avec cURL : http://www.epsi.fr/Programmes/Panorama-des-etudes et http://www.google.com. Essayez ensuite d'utiliser la méthode HEAD puis la méthode POST plutôt que la méthode GET dans vos requêtes. Quelles différences constatez-vous ?

Les codes de statut

Dans la ligne de réponse, le serveur transmet le code de statut du traitement de la requête. Il s'agit d'un nombre sur 3 chiffres. Les codes de statut HTTP sont regroupés par familles identifiées par le chiffre des centaines.

Parmi les codes existants, certains sont plus remarquables et doivent être connus :

Famille Code Libellé Description
2XX 200 OK Le traitement de la requête est un succès et la réponse contient un message correspondant au résultat du traitement.
201 Created La requête est un succès et sa prise en compte a entraîné la création d'une ou plusieurs ressources.
204 No Content La requête est un succès et la réponse ne contient pas de message.
3XX 301 Moved Permanently Indique que le serveur connaît la ressource à laquelle le client désire accéder mais qu'elle n'est plus disponible à l'URI spécifiée. L'en-tête de réponse Location permet au serveur d'indiquer la nouvelle URI à laquelle le client pourra accéder à la ressource.
303 See Other La requête a été exécutée mais la réponse doit être consultée à une autre URI. L'en-tête de réponse Location permet au serveur d'indiquer l'URI vers laquelle le client peut exécuter un GET pour accéder au résultat.
307 Temporary redirect La requête n'a pas été traitée par le serveur et le client doit refaire la même requête vers une URI différente. L'en-tête de réponse Location permet au serveur d'indiquer la nouvelle URI à laquelle le client pourra renvoyer sa requête.
304 Not Modified Code d'état utilisé lors d'une requête conditionnelle pour spécifier au client que la ressource n'a pas été modifiée depuis son dernier accès. Il s'agit d'une redirection car ce code est utilisé la plupart du temps pour la gestion de la mise en cache. Le serveur notifie ainsi le client qu'il peut utiliser la représentation qu'il a déjà obtenue (et mise en cache) lors de son dernier accès.
4XX 400 Bad Request La requête n'a pas pu être traitée car elle est syntaxiquement incorrecte.
404 Not Found Le serveur ne dispose pas de représentation pour la ressource cible.
405 Method Not Allowed La ressource cible est connue du serveur mais le client ne peut pas utiliser la méthode spécifiée dans la requête.
406 Not Acceptable Indique qu'il n'existe pas de représentation au format demandé par le client pour la ressource cible (échec de la négociation de contenu).
409 Conflict La requête ne peut pas être traitée sans entrer en conflit avec l'état courant d'une ressource sur le serveur.
412 Precondition failed Lors d'une requête conditionnelle, indique que la requête n'a pas pu être traitée car une de ses préconditions n'est pas satisfaite.
415 Unsupported Media Type Indique que le message envoyé par le client utilise un format qui n'est pas supporté par le serveur. Par exemple, le client envoie au serveur un message au format XML alors que ce dernier s'attend à un document PDF.
5XX 500 Internal Server Error Une erreur inattendue a empêché le serveur de traiter la requête.

Les méthodes HTTP

Les méthodes HTTP désignent le type d'opération que le client désire réaliser. Attention, leur nom s'écrit en majuscules dans une requête HTTP.

GET
Demande au serveur une représentation de la ressource cible.
HEAD
Comme un GET sauf que la réponse ne contient jamais de corps. Cette méthode est utile pour obtenir les informations des en-têtes et valider une requête sans envoyer ni recevoir de corps de message.
PUT
Crée ou met à jour l'état d'une ressource identifiée par l'URI.
PATCH
Change partiellement l'état d'une ressource cible. PATCH ne fait pas partie de la liste initiale des méthodes HTTP. Elle a été ajoutée en 2010 par la RFC 5789.
DELETE
Détruit l'association de l'URI avec l'état de la ressource.
POST
La sémantique de la méthode POST est probablement la plus compliquée à saisir car cette méthode est utilisable dans différentes situations pour :
  • Fournir un bloc de données (formulaire) à un processus de traitement
  • Poster un message dans un système de centralisation d'articles
  • Créer une nouvelle resource qui sera identifiée par le serveur
  • Ajouter des informations à la représentation d'une ressource

Lorsqu'un client reçoit une réponse à une méthode POST, il peut être important de savoir si la réponse correspond à une représentation d'une ressource ou s'il s'agit du résultat d'un traitement. Pour un code statut 200, l'en-tête de réponse Content-Location sert à faire cette différence. S'il est présent, l'en-tête Content-Location signale que le corps de la réponse correspond bien à la représentation d'une ressource dont l'URI est donnée par cet en-tête.

OPTIONS
Permet d'obtenir les options de communication (par exemple : les méthodes autorisées pour l'URI). Le serveur doit retourner ces informations dans les en-têtes de réponse. Ainsi l'en-tête de réponse Allow liste les méthodes HTTP autorisées pour cette URI.
TRACE
Permet de simuler un écho de la requête. Cette méthode n'est pas utilisée pour la réalisation d'API Web car elle est surtout utile pour tester la configuration du réseau et obtenir des informations des proxies.
CONNECT
Établit un tunnel à travers un proxy. Cette méthode n'est pas utilisée pour la réalisation d'API Web.

Propriétés des méthodes HTTP

Les méthodes HTTP sont classées selon trois propriétés : la sûreté, l'idempotence et le support du cache (cacheable).

Sûreté (safety)
Une méthode est sûre si le client ne s'attend à aucune modification d'état sur le serveur. Une méthode sûre est assimilable à une simple lecture de données. En tant que telle, elle doit pouvoir être exécutée entre 0 et N fois sans que cela n'affecte la ressource associée. Les méthodes GET, HEAD et OPTIONS doivent être sûres.
Idempotence (idempotent)
Une méthode est idempotente si l'effet obtenu est le même qu'elle soit exécutée 1 ou N fois. Autrement dit, toutes choses étant égales par ailleurs, la répétition d'une requête utilisant une méthode idempotente conduit au même résultat. Les méthodes GET, HEAD, OPTIONS, PUT et DELETE doivent être idempotentes.

En HTTP, la notion d'idempotence est fortement associée à la reprise sur erreur. En effet, les requêtes utilisant des méthodes idempotentes peuvent être répétées en cas d'erreur de communication. Par exemple, si un client emet une requête DELETE et qu'il n'obtient pas de réponse du serveur, il peut émettre à nouveau sa requête jusqu'à obtenir une réponse. Cela fait de HTTP un protocole adapté pour des réseaux connectés mais peu fiables (Wifi, réseau data de téléphonie mobile...)

Support du cache (cacheable)
Une méthode cacheable indique que sa réponse peut être stockée par le client ou un proxy pour une utilisation ultérieure. Attention, il ne s'agit en rien d'une règle obligatoire et la gestion du cache en HTTP est régie par la RFC 7234. HTTP définit les méthodes GET, HEAD et POST comme étant cacheables. Les méthodes non cacheables forcent la suppression des données mises en cache pour l'URI lorsqu'elles sont soumises au serveur.
  Sûre Idempotente Cacheable
GET oui oui oui
HEAD oui oui oui
PUT non oui non
PATCH non non non
DELETE non oui non
POST non non oui
OPTIONS oui oui non

Les en-têtes HTTP

Les en-têtes de requête et de réponse permettent d'enrichir le contexte de la requête ou la réponse. Ils servent à fournir des données pour le support d'un ensemble de fonctionnalités de HTTP :

A titre d'exemple, on citera :

Host (requête)
L'en-tête Host est le seul obligatoire en HTTP 1.1 pour un requête. Il contient le nom et le port du serveur. Sa présence permet notamment la gestion de serveurs HTTP virtuels sur un même port.
Une requête HTTP avec l'en-tête Host
GET / HTTP/1.1
Host: www.monserveur.fr:9090
					
Content-Type (requête et réponse)
Si une requête ou une réponse contient un message, il est nécessaire pour le destinataire d'identifier le format du contenu. L'en-tête HTTP Content-Type fournit cette information sous la forme d'un type MIME.

Une liste (non exhaustive) des types MIME les plus courants est :

text/plain Un fichier texte
text/plain;charset=utf-8 Un fichier texte encodé en UTF-8
text/html Un fichier HTML
text/xml ou application/xml Un fichier XML
text/json ou application/json Un fichier JSON
image/jpeg Une image au format jpeg
application/x-www-form-urlencoded Le format de données pour la soumission d'un formulaire HTML
application/octet-stream Un flux d'octets sans type particulier. Il s'agit du format par défaut si l'en-tête Content-type est absent.
Une requête HTTP avec l'en-tête Content-Type
POST /utilisateur HTTP/1.1
Host: www.monserveur.fr:9090
Content-Type: application/x-www-form-urlencoded
Content-Length: 36

nom=David&prenom=Gayerie&taille=174

Content-Length (requête et réponse)
Si une requête ou une réponse contient un message, il est nécessaire pour le destinataire d'en connaître la taille afin d'identifier la fin du message HTTP. En effet le mécanisme HTTP du pipelining permet de soumettre plusieurs requêtes (et donc de recevoir plusieurs réponse) sur une même connexion TCP. La capacité de délimiter les requêtes d'une part et les réponses d'autre part est donc cruciale. L'en-tête Content-Length sert à communiquer la taille en octets du message.
Une requête HTTP avec l'en-tête Content-Length
POST /utilisateur HTTP/1.1
Host: www.monserveur.fr:9090
Content-Type: application/x-www-form-urlencoded
Content-Length: 36

nom=David&prenom=Gayerie&taille=174

Une réponse HTTP avec l'en-tête Content-Length
HTTP/1.1 200 OK
Content-Type: text/plain; charset=utf-8
Content-Length: 17

Hello the world!