============================== Bases de la pogrammation Web ============================== .. role:: en .. role:: lat .. |framework| replace:: `framework`:en: Rappels sur le Web ================== Web ≠ Internet -------------- Internet est ensemble de réseaux informatiques locaux utilisant les mêmes protocoles de bas niveau standards (TCP/IP) et formant un réseau global. .. figure:: InternetMonde.* Image © portices.fr__ __ http://www.portices.fr/formation/Res/Internet/Res/InternetMonde.gif .. note:: Le Web est *l'une* des applications d'internet, et la plus populaire, d'où l'amalgamme souvent fait entre les deux. Qu'est-ce que le Web ? ---------------------- Un espace documentaire décentralisé, interconnecté et interopérable. .. rst-class:: build * décentralisé → **HTTP** * interconnecté → **URL** * interopérable → **HTML** .. note:: Ces technologies peuvent bien sûr évoluer (elle l'ont déjà fait), voire être à terme remplacées par d'autres. Ce ne sont pas elles qui définissent le Web, mais les 3 propriétés qu'elles lui confèrent. Architecture du Web =================== Architecture Client-Serveur --------------------------- * **Ressource**: toute unité d'information (document, image, vidéo, données...) accessible sur le Web, **identifiée par une URL** * **Serveur**: un ordinateur « contenant » des ressources, toujours connecté à Internet. * **Client**: un ordinateur/smartphone/tablette... utilisé pour **exploiter** des ressources. .. figure:: client-server.* :height: 8ex Source image http://commons.wikimedia.org/wiki/File:Client-server-model.svg .. note:: * Les termes "client" et "serveur" identifient en fait des *rôles*. * Le même ordinateur peut jouer le rôle de client dans certaines situations, et de serveur dans d'autres situations. * Il est même possible d'avoir, sur un *même ordinateur*, un logiciel client et un logiciel serveur (c'est ce que nous dans la plupart des TPs). Identification des ressources ----------------------------- .. raw:: html :file: url-structure1.html * Le nom local a souvent une structure hiérarchique (similaire à la structure des fichiers). * Comme pour les fichiers, on peut spécifier une URL *relativement* à une autre : exemple : ``../algorithmique`` .. warning:: Malgré cette similitude, les ressources ne correspondent *pas toujours* à des fichiers. .. nextslide:: * Plus généralement, le nom local est composé de plusieurs parties, ayant des structures différentes. Son interprétation est du ressort *du serveur*. .. raw:: html :file: url-structure2.html * *Chaque* URL désigne une **ressource différente** (même lorsqu'elle ne diffère que par les paramètres, par exemple) Rôles du serveur ---------------- * Est garant de l'état des ressources, * pour en fournir une *représentation* aux clients qui le demandent (GET), * mais aussi pour les *modifier* en réponse à certaines requêtes (POST), par exemple : - commande sur un site marchand, - message posté sur un réseau social, - `etc`:lat:... .. important:: L'état d'une ressource n'est pas forcément stocké dans un fichier. Souvent, il est stocké dans une base de données ; la représentation HTML (ou autre) de la ressource est calculée par le serveur. Rôles du client --------------- * Interprète les représentation envoyées par le serveur (pour les afficher, mais pas uniquement) * Gère la navigation en interne * Gère les interactions avec le serveur : - clics sur des liens, - formulaires, - `etc`:lat:... Message HTTP ============ Principe -------- HTTP est basé sur l'échange de **messages** : * le client envoie un message *requête*, * le serveur retourne un message *réponse*. Chaque échange est indépendant des autres (messages auto-suffisants). Structure générale ------------------ .. image:: envelope.svg Structure d'une requête ----------------------- * Première ligne - verbe - identifiant local de la ressource - version du protocole HTTP * En-têtes (suivis d'une ligne vide) * Contenu facultatif (selon le verbe) Exemples de requêtes -------------------- .. rst-class:: request .. code-block:: http :emphasize-lines: 1 GET /france/lyon HTTP/1.1 Host: meteo.example.org User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:58.0) Gecko/20100101 Firefox/58.0 Accept: text/html,application/xhtml+xml, application/xml;q=0.9,*/*;q=0.8 Accept-Language: fr,en;q=0.5 Accept-Encoding: gzip,deflate Accept-Charset: UTF-8,* Connection: keep-alive Keep-Alive: 300 (pas de contenu) ---- .. nextslide:: :increment: .. rst-class:: request .. code-block:: http :emphasize-lines: 1 GET /france?ville=lyon HTTP/1.1 Host: meteo.example.org User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:58.0) Gecko/20100101 Firefox/58.0 Accept: text/html,application/xhtml+xml, application/xml;q=0.9,*/*;q=0.8 Accept-Language: fr,en;q=0.5 Accept-Encoding: gzip,deflate Accept-Charset: UTF-8,* Connection: keep-alive Keep-Alive: 300 (pas de contenu) ---- .. nextslide:: :increment: .. rst-class:: request .. code-block:: http :emphasize-lines: 1 POST /passer-commande HTTP/1.1 Host: marchand.example.org User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:58.0) Gecko/20100101 Firefox/58.0 Accept: text/html,application/xhtml+xml, application/xml;q=0.9,*/*;q=0.8 Accept-Language: fr,en;q=0.5 Accept-Encoding: gzip,deflate Accept-Charset: UTF-8,* Connection: keep-alive Keep-Alive: 300 Content-Type: application/x-www-form-urlencoded Content-Length: 12345 nom=PA+Champin&addresse=42+rue+Turing&articles=... .. note:: * On retrouve dans la requête la structure de l'URL (nom du serveur, nom local de la ressource) * Notez que les deux premières requêtes sont identiques, à l'exception du nom local. Structure d'une réponse ----------------------- * Première ligne - version du protocole HTTP - code de statut - libellé textuel * En-têtes (suivis d'une ligne vide) * Contenu facultatif (selon le code de statut) Exemples de réponse ------------------- .. rst-class:: response .. code-block:: http :emphasize-lines: 1 HTTP/1.1 200 OK Date: Mon, 02 Jan 2016 22:46:26 GMT Server: Apache/2 Accept-Ranges: bytes Content-Type: text/html; charset=utf-8 Content-Length: 29794 Etag: "7462-477341dcfb940;89-3f26bd17a2f00" Last-Modified: Mon, 02 Jan 2016 12:00:00 GMT Content-Location: Home.html Vary: negotiate,accept Cache-Control: max-age=600 Expires: Mon, 02 Nov 2009 22:56:26 GMT Connection: close Météo de Lyon ... .. nextslide:: :increment: .. rst-class:: response .. code-block:: http :emphasize-lines: 1 HTTP/1.1 303 See also Date: Mon, 02 Jan 2016 22:46:26 GMT Server: Apache/2 Accept-Ranges: bytes Location: /commande/12345 Connection: close (pas de contenu) ---- .. nextslide:: :increment: .. rst-class:: response .. code-block:: http :emphasize-lines: 1 HTTP/1.1 404 Not Found Date: Mon, 02 Jan 2016 22:46:26 GMT Server: Apache/2 Content-Type: text/html; charset=utf-8 Content-Length: 2979http://rdflib.readthedocs.io/ Connection: close Cette ressource n'existe pas ... Codes de statut --------------- HTTP définit 40 codes de statut, répartis en cinq catégories : .. list-table:: :header-rows: 1 * - Catégories - Exemples * - 1xx : Information - 100 Continue * - 2xx : Succès - 200 OK * - 3xx : Redirection - 301 Moved Permanently * - 4xx : Erreur client - 404 Not Found, 401 Unauthorized * - 5xx : Erreur serveur - 500 Internal Server Error En-têtes de requête ------------------- .. note:: HTTP spécifie un *très grand nombre* d'en-têtes ; nous décrirons au fur et à mesure du cours ceux dont nous avons besoin. * ``accept``: la liste des types de contenu (au format `MIME`_) préférés le client. * ``accept-language``: la liste des langues (au format `BCP47`_) préférés par le client. Ces en-têtes servent à la *négociation de contenu* (*conneg*). Le serveur *peut* utiliser ces informations pour *adapter* le contenu de la réponse, mais il peut aussi les ignorer (lorsque la ressources est un fichier statique). .. _MIME: https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_Types .. _BCP47: https://tools.ietf.org/html/bcp47 * ``cache-control``: permet d'influer sur le comportement des caches intermédiaires, notamment pour les inhiber (option ``no-cache``). En-têtes de réponse -------------------- * ``content-type``: le type de contenu de la réponse (au format `MIME`_). Exemple: ``text/html``, ``image/png``, ``application/pdf``. * ``content-length``: la taille du message en octets. * ``cache-control``: permet d'influer sur le comportement des caches, notamment pour indiquer la durée de validité maximale (option ``max-age=``). .. note:: les en-têtes ``content-type`` et ``content-length`` sont en fait utilisés pour tout message ayant un contenu, y compris certaines *requêtes* (`e.g.`:lat: POST). Serveur et application ====================== Architecture générale --------------------- .. graphviz:: serveur.dot :caption: Les ressources du serveur peuvent être gérées de différentes manières .. note:: * Certaines ressources sont stockées directement dans des fichiers statiques (dont le nom est en général corrélé avec le chemin de l'URL). * Certaines ressources sont gérées par un script PHP. * Certaines ressources sont gérées par un programme, répondant à certains standards, comme - `CGI `_, - WSGI, que nous allons utiliser dans ce module, - ... WSGI ---- WSGI_ (`Web Server Gateway Interface`:en:) est un standard spécifiant comment un serveur Web peut interagir avec une application Python. .. _hello_world_wsgi: .. code-block:: python # exemple basique d'application Web en WSGI def application(environ, start_response): message = b"Hello world\n" status = "200 Ok" headers = [ ("content-type", "text/html"), ("content-length", str(len(message))), ] start_response(status, headers) return [message] Il n'offre qu'un faible niveau d'abstraction. .. note:: Cela s'explique par l'objectif de WSGI_ est d'être compatible avec * un maximum de serveurs, et * un maximum d'applications Web. Il doit donc rester le plus générique possible. Qu'est-ce qu'un |framework| ? ----------------------------- * Une boîte à outils logicielle * destinés à *un certain type* d'applications Web, * offrant des fonctionnalités de haut niveau, * et favorisant la mise en œuvre de bonnes pratiques. `Frameworks`:en: Web en Python ------------------------------ * `Django `_ * `Flask `_ * `Pyramid `_ * `CherryPy `_ * `Twisted `_ * ... .. _premiers-pas-en-flask: Premiers pas en Flask ===================== .. note:: Ce chapitre présente les notions de bases dont vous aurez besoin pour le `../tp/tp3`:doc:. Pour plus de détail, consultez le chapitre de cours suivant : `cm2`:doc:. Hello World Flask ----------------- .. code-block:: python from flask import Flask app = Flask(__name__) @app.route("/greeting") def greeting(): return "Hello world" Explications ------------ * ``app`` est une *application* Flask; elle est entre-autre homogène à une fonction WSGI_, donc elle peut être utilisée par un serveur compatible. * La fonction ``greeting`` est appelée une *vue*. Elle retourne une chaîne de *caractères*, qui sera le contenu de la réponse. Par défaut, le statut de la réponse est 200, et le type de contenu est HTML, encode en UTF-8. On verra plus tard comment générer d'autres types de réponses. * La ligne qui précède la fonction ``greeting`` est un `décorateur <318>`:pep: python. Il sert à indiquer l'URL pour laquelle cette vue doit être utilisée. .. note:: Par rapport à l'`exemple WSGI vu précédemment `:ref:, ce programme est plus simple, et gère déjà plus de choses : * il ne répond que sur l'URL ``/greetings``, toute autre URL répondra par une erreur ``404 Not Found`` ; * il ne répond qu'aux requêtes GET, une autre méthode (par exemple POST) répondra par une erreur ``405 Method Not Allowed`` ; * il répond correctement aux requêtes HEAD (i.e. en-têtes dans contenu). .. _serveur_dev: Serveur de développement ------------------------ * Il n'est pas forcément aisé de mettre en place un serveur Web pour tester notre application. * Flask fournit son propre *serveur de développement*, directement dans la méthode ``run`` de l'application. On peut donc créer un script ``serveur.py`` contenant simplement : .. code-block:: python # en supposant que votre application Flask est définie # dans un fichier nommé 'mon_projet.py' from mon_projet import app app.run(debug=True) .. nextslide:: * Le mode ``debug`` offre de plus des fonctions avancées, notamment : + le recharchement automatique des fichiers python en cas de modification, + l'affichage des exceptions dans le navigateur, + la possibilité d'interagir avec le code python depuis le navigateur en cas d'erreur. Routes ------ * En développement Web, on appelle route une URL ou un ensemble d'URLs conduisant à l'exécution d'une fonction donnée. * Dans Flask, les routes sont déclarées `via`:lat: le décorateur ``app.route``, comme dans l'exemple ci-dessus. * Une route peut être *paramétrée*, auquel cas le paramềtre sera passé à la fonction vue :: @app.route("/hello/") def hello(name): return "Hello %s" % name Réponse personnalisée --------------------- Il est possible pour une vue de retourner un objet ``Response`` (au lieu d'une chaîne de caractères) dont on peut alors personnaliser les méta-données. Cet objet peut être produit grâce à la fonction ``flask.make_response``. Exemple :: @app.route("/some.pdf") def some_pdf(): pdf_data = produce_pdf_data() resp = make_response(pdf_data) resp.headers["content-type"] = "application/pdf" return resp .. _WSGI: https://www.python.org/dev/peps/pep-3333/