Cet article a été initialement traduit par MaNong.com – Xiao Hao Veuillez lire les exigences de réimpression à la fin de l'article pour la réimpression. Bienvenue pour participer à notre plan de contribution payante.
À la base de Django, Flask, Bottle et de tous les autres frameworks Web Python se trouve l'interface Web Server Gateway, ou WSGI en abrégé. WSGI est à Python ce que les servlets sont à Java : une spécification commune pour les serveurs Web qui permet à différents serveurs Web et cadres d'application d'interagir sur la base d'une API commune. Cependant, pour la plupart des choses, la version Python est assez simple à mettre en œuvre.
WSGI est défini dans le protocole PEP 3333 Si vous souhaitez en savoir plus après avoir lu cet article, l'auteur recommande aux lecteurs de lire d'abord l'introduction.
Cet article vous présentera les instructions WSGI du point de vue d'un développeur d'applications et vous montrera comment développer des applications directement via WSGI (si vous ne pouvez pas attendre).
Voici l'application web Python la plus basique :
def app(environ, start_fn): start_fn('200 OK', [('Content-Type', 'text/plain')]) return ["Hello World!\n"]
C'est tout ! tout le dossier. Nommez-le app.py et exécutez-le sur n'importe quel serveur compilable WSGI, et vous obtiendrez un Hello World avec un code d'état de réponse de 200. Vous pouvez utiliser gunicorn pour ce faire, installer et exécuter gunicorn app:app via pip (pip install gunicorn). Cette commande indique à gunicorn d'obtenir le WSGI appelable à partir des variables d'application dans le module d'application.
J'étais très excité à l'instant. Pouvez-vous exécuter une application avec seulement trois lignes de code ? Cela doit être une journalisation dans un certain sens (à l'exclusion de PHP, puisque mod_php est en jeu). Je parie que vous voulez en savoir plus maintenant.
Alors, quelle est la partie la plus importante d’une application WSGI ?
Une application WSGI est une application Python appelable, comme une fonction, une classe ou une instance de classe avec une méthode __call__
Une application appelable doit accepter deux arguments : environ, un dictionnaire Python contenant les données nécessaires, et start_fn, qui est lui-même appelable.
L'application doit pouvoir appeler start_fn avec deux paramètres : le code d'état (string), et une liste représentée par un en-tête de deux tuples.
L'application renvoie un objet itérable pratique contenant des octets dans le corps de retour, la partie streaming - par exemple, chacun contenant uniquement la liste de chaînes "Hello, World!". (Si app est une classe, cela peut se faire dans la méthode __iter__)
Par exemple, les deux exemples suivants sont équivalents au premier :
class app(object): def __init__(self, environ, start_fn): self.environ = environ self.start_fn = start_fn def __iter__(self): self.start_fn('200 OK', [('Content-Type', 'text/plain')]) yield "Hello World!\n"
class Application(object): def __call__(self, environ, start_fn): start_fn('200 OK', [('Content-Type', 'text/plain')]) yield "Hello World!\n" app = Application()
Vous avez peut-être commencé à réfléchir à l'utilisation que vous pouvez faire de ces éléments, mais le plus pertinent est d'écrire un middleware.
Le middleware est un moyen pratique d'étendre les fonctionnalités des applications WSGI. Puisque vous devez uniquement fournir un objet appelable, vous pouvez l'envelopper dans n'importe quelle autre fonction.
Par exemple, supposons que nous souhaitions détecter le contenu de environ. On peut facilement créer un middleware pour accomplir cela comme suit :
import pprint def handler(environ, start_fn): start_fn('200 OK', [('Content-Type', 'text/plain')]) return ["Hello World!\n"] def log_environ(handler): def _inner(environ, start_fn): pprint.pprint(environ) return handler(environ, start_fn) return _inner app = log_environ(handler)
Ici, log_environ est une fonction qui renvoie une fonction dans le paramètre environ Décorez ce paramètre avant de retarder le rappel initial.
L'avantage d'écrire un middleware de cette manière est que le middleware et le processeur n'ont pas besoin de se connaître ou de se soucier l'un de l'autre. Vous pouvez facilement lier log_environ à une application Flask, par exemple, car l'application Flask est une application WSGI.
Quelques autres conceptions de middleware utiles :
import pprint def handle_error(handler): def _inner(environ, start_fn): try: return handler(environ, start_fn) except Exception as e: print e # Log error start_fn('500 Server Error', [('Content-Type', 'text/plain')]) return ['500 Server Error'] return _inner def wrap_query_params(handler): def _inner(environ, start_fn): qs = environ.get('QUERY_STRING') environ['QUERY_PARAMS'] = urlparse.parse_qs(qs) return handler(environ, start_fn) return _inner
Si vous ne souhaitez pas que votre fichier ait une grande base pyramidale, vous pouvez utiliser réduire une fois appliqué à plusieurs middlewares.
# Applied from bottom to top on the way in, then top to bottom on the way out MIDDLEWARES = [wrap_query_params, log_environ, handle_error] app = reduce(lambda h, m: m(h), MIDDLEWARES, handler)
En utilisant les avantages du paramètre start_fn, vous pouvez également écrire un middleware qui décore le corps de la réponse. Vous trouverez ci-dessous un middleware dont l'en-tête de type de contenu est text/plain pour inverser le résultat de sortie.
def reverser(handler): # A reverse function rev = lambda it: it[::-1] def _inner(environ, start_fn): do_reverse = [] # Must be a reference type such as a list # Override start_fn to check the content type and set a flag def start_reverser(status, headers): for name, value in headers: if (name.lower() == 'content-type' and value.lower() == 'text/plain'): do_reverse.append(True) break # Remember to call `start_fn` start_fn(status, headers) response = handler(environ, start_reverser) try: if do_reverse: return list(rev(map(rev, response))) return response finally: if hasattr(response, 'close'): response.close() return _inner
C'est un peu déroutant à cause de la séparation de start_fn et du corps de réponse, mais cela fonctionne toujours parfaitement.
Notez également que afin de suivre strictement la spécification WSGI, nous devons vérifier la méthode close dans le corps de la réponse et l'appeler si elle existe. Il est possible qu'une application WSGI renvoie une fonction write au lieu d'un objet itérable appelant le gestionnaire, et vous devrez peut-être gérer cela si vous souhaitez que votre middleware prenne en charge des applications plus anciennes.
Une fois que vous commencez à jouer un peu avec WSGI natif, vous commencez à comprendre pourquoi Python dispose de nombreux frameworks Web. WSGI permet de créer très facilement quelque chose à partir de zéro. Par exemple, vous envisagez peut-être le problème de routage suivant :
routes = { '/': home_handler, '/about': about_handler, } class Application(object): def __init__(self, routes): self.routes = routes def not_found(self, environ, start_fn): start_fn('404 Not Found', [('Content-Type', 'text/plain')]) return ['404 Not Found'] def __call__(self, environ, start_fn): handler = self.routes.get(environ.get('PATH_INFO')) or self.not_found return handler(environ, start_fn)
Si vous aimez la flexibilité de la collection de ressources suivante, il est très pratique d'utiliser directement WSGI pour créer la roue.
Bibliothèque de modèles : ajoutez n'importe quel modèle que vous aimez (par exemple Jinja2, Pystashe) et renvoyez le modèle rendu depuis votre processeur !
Utilisez une bibliothèque pour vous aider avec le routage, comme Routes ou le routage de Werkzeug. En fait, si vous souhaitez utiliser WSGI facilement, jetez un œil à Werkzeug.
Utilisez n'importe quelle bibliothèque de migration de base de données Flask ou similaire.
Bien sûr, pour les applications non professionnelles, vous pouvez également utiliser un framework, afin que certains exemples particuliers comme celui-ci puissent également être raisonnablement résolus.
Il existe de nombreuses façons de servir les applications WSGI. Nous avons déjà parlé de Gunicorn, un très bon choix. uWSGI est un autre bon choix. Mais assurez-vous de configurer des éléments comme nginx avant de diffuser ces éléments statiques, et vous devriez avoir un nœud de départ fixe.
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!