Bases de la pogrammation Web§

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.

../_images/InternetMonde.png

Image © portices.fr

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.

  • 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.

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§

 ┌──────────────────── protocole
 │      ┌───────────── serveur
 │      │           ┌─ nom local
 │      │           │
─┴──   ─┴───────── ─┴──────────────
http://champin.net/enseignement/web
  • 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

Avertissement

Malgré cette similitude, les ressources ne correspondent pas toujours à des fichiers.

  • 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.
 ┌──────────────────── protocole
 │      ┌───────────── serveur
 │      │           ┌─ nom local
 │      │           │
─┴──   ─┴───────── ─┴─────────────
http://champin.net/a/b/c?d=1&e=2#f
                   ───┬─ ─────┬─ ┬
                      │       │  │
partie hiérarchique   │       │  │
            (chemin) ─┘       │  │
 partie associative           │  │
        (paramètres) ─────────┘  │
     partie interne(fragment) ────────────┘
  • 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...

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...

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§

../_images/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§

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)


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)


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§

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

<!DOCTYPE html>
<html><head><title>Météo de Lyon</title>
...
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)

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

<!DOCTYPE html>
<html><head><title>Cette ressource n'existe pas</title>
...

Codes de statut§

HTTP définit 40 codes de statut, répartis en cinq catégories :

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).

  • 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=<seconds>).

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. POST).

Serveur et application§

Architecture générale§

digraph {
  rankdir=LR;
  edge [arrowTail=normal; dir=both];
  client -> serveur
  serveur -> fichier
  serveur -> PHP
  serveur -> "programme CGI"
  serveur -> "python (WSGI)"
  serveur -> "..."
}

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) est un standard spécifiant comment un serveur Web peut interagir avec une application 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 Web en Python§

Premiers pas en Flask§

Note

Ce chapitre présente les notions de bases dont vous aurez besoin pour le TP n°3 : Première application Flask.

Pour plus de détail, consultez le chapitre de cours suivant : Le framework Flask.

Hello World Flask§

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 python. Il sert à indiquer l’URL pour laquelle cette vue doit être utilisée.

Note

Par rapport à l’exemple WSGI vu précédemment, 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 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 :

    # 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)
    
  • 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 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/<name>")
    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