==============================
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/