PROJET AUTOBLOG


Sam et Max

source: Sam et Max

⇐ retour index

Qu’est-ce que WSGI et à quoi ça sert ?

mercredi 3 juillet 2013 à 12:36

On va dire que je me répète, mais WSGI est typiquement le cas d’une notion simple et super mal expliquée sur le Web.

C’est terrible ça, une vrai maladie. Ça me donne envie de faire des vidéos comme le joueur du Grenier pour râler à voix haute.

Bref.

Donc WSGI a le même but que FastCGI, SCGI, or AJP : c’est une norme qui sert à définir comment un serveur Python et son application peuvent discuter. Ça été pondu pour que tous les serveurs et toutes les applications Python qui respectent la norme soient garantis de pouvoir s’interfacer.

Ça, c’est la définition que vous voyez partout. Super, mais concrètement ça veut dire quoi ?

WSGI, c’est juste une convention de discussion

Un bon dessin vaut mieux…

Schéma du fonctionnement de WSGI

C'est compliqué de faire un schéma comme ça sérieux ? Ah ça pond une norme de 30 pages mais ça peut pas faire 3 ronds dans paint.

D’un côté vous avez des serveurs comme ceux de cherrypy, de paste, de werkzeug ou comme la commande runserver de Django, ou tels que les serveurs gunicorn, Apache (avec mod_wsgi). Ces logiciels ont pour boulot d’accueillir une requête HTTP et de renvoyer la réponse. Ils ont des problématiques comme : gérer les sockets, gérer plusieurs processus en parallèle, éviter qu’un pirate se balade sur votre serveur, etc.

De l’autre côté vous avez votre application. 9 fois sur 10, votre site Web, donc votre code. Sa problématique c’est de recevoir une requête, la comprendre, et générer une réponse en tapant dans la base de données, et en faisant sa popotte HTML.

Il faut donc que votre serveur dialogue avec votre app, qu’il lui passe la requête, que votre app la gère, retourne la réponse, et file la réponse au serveur. Alors le serveur envoie la réponse au navigateur.

C’est la chose la plus mal expliquée : il y a deux parties à WSGI. Une pour le serveur, et une pour l’application.

Un serveur est dit “compatible WSGI” quand il est capable de transmettre une requête HTTP normale à votre application via le protocole WSGI, et qu’il est capable de récupérer une réponse HTTP depuis votre application via le protocole WSGI pour en faire une requête HTTP normale.

Une application est dite “compatible WSGI” quand elle est capable de recevoir une requête HTTP transformée en un objet Python selon la norme WSGI, et qu’elle retourne une réponse HTTP sous la forme d’un objet Python selon la norme WSGI.

J’avais demandé concrètement, show me the fucking code !

Côté serveur WSGI, on doit lui passer le point d’entrée de votre app.

Le point d’entrée est un module Python qui contient une variable nommé application.

C’est tout.

La variable application doit contenir votre application compatible WSGI.

Une application compatible WSGI a un certain nombre de méthodes pour accepter en paramètres un objet requête HTTP, et retourner un objet réponse HTTP, mais la bonne nouvelle, c’est que vous n’avez absolument pas besoin de savoir comment ça marche.

En effet, tous les frameworks compatibles WSGI (bottle, django, cherrypy, etc) ont une fonction qui retourne cette application toute faite.

Par exemple, avec bottle, mon fichier wsgi va contenir :

from site import app
 
application = app

C’est tout. app, le décorateur qui permet de faire @app.route('/') dans le code du site bottle, est déjà une application WSGI.

Pour Django, ça va donner un truc comme :

import os
# ont dit quel est le module de settings Django
os.environ["DJANGO_SETTINGS_MODULE"] = "project.settings"
 
# et on fabrique l'application WSGI avec une fonction
# que Django nous donne
from django.core.wsgi import get_wsgi_application
 
application = get_wsgi_application()

Le simple fait qu’il y ait une variable nommée application fait que le serveur va se débrouiller. Tout ce qu’il y a à faire, c’est passer en paramètre ce module au serveur, et comment le faire dépend du serveur.

Par exemple pour gunicorn, c’est le premier paramètre de la commande qu’on utilise pour lancer le serveur :

gunicorn nom_du_module

Il faut que le module soit importable (on peut passer l’option --pythonpath pour s’en assurer.)

Pour Apache et mod_wsgi, ça se fait dans le fichier de config apache.conf:

WSGIScriptAlias / /chemin/version/module.wsgi

Bref, faire dialoguer un serveur et une application WSGI, c’est con comme la lune :

  1. Faire un module qui contient une variable nommée application contenant l’app WSGI.
  2. Dire au serveur où se trouve le fichier

Avantages et inconvénients de WSGI

Parmi les avantages, on retrouve :

Quant aux inconvénients :

Pour la culture

Voici à quoi ressemble un hello world en WSGI :

def application(environ, start_response):
    start_response('200 OK', [('Content-Type', 'text/plain')])
    yield 'Hello World\n'

Et oui, c’est très simple, et il n’y a rien à importer. La norme WSGI est une convention : il doit y avoir une variable nommée application (ici la variable c’est le nom de la fonction), et cette variable doit contenir une application WSGI.

Mais une application WSGI, c’est juste un callable (ici une fonction) qui accepte en paramètres environ (la requête), start_response (une fonction qui écrit l’en-tête de la réponse) et qui retourne un générateur de string. C’est tout.

Il n’y a rien de magique. C’est une simple interface sur laquelle tout le monde s’est mis d’accord.

Quand on fait en Django:

application = get_wsgi_application()

En fait Django ne fait que fabriquer une fonction comme on vient de voir, qui derrière appelle votre application Django.

En revanche, comme on utilise souvent Django derrière nginx, le setup ressemble très souvent à ça :

Schém d'utilistation de WSGI avec Nginx

Quand on voit "socket", ça fait peur, mais c'est juste une ligne de config qui point généralement vers localhost:8000.

flattr this!