Erstelle eine Web App mit purem Python (Ohne Flask, kein Django, keine Frameworks!)
Grace Collins
Solutions Engineer · Leapcell

Erstellen der minimalen Python Webanwendung mit WSGI
Wer Python Webanwendungen geschrieben hat, insbesondere wer Online-Deployments durchgeführt hat, muss vom WSGI-Protokoll gehört haben. Es definiert die Datenaustausch-Schnittstelle zwischen den Webservern von Python und den Webanwendungen. Diese Beschreibung mag etwas abstrakt sein, daher wollen wir sie anhand von praktischen Beispielen im Detail erläutern.
Deployment von Webanwendungen in einer Produktionsumgebung
Angenommen, wir haben eine Webanwendung mit einem Webanwendungs-Framework wie Django oder Flask entwickelt. Die offizielle Dokumentation dieser Frameworks weist in der Regel darauf hin, dass die eingebauten Server der Frameworks, wie z.B. python manage.py runserver
in Django oder flask --app hello run
in Flask, nur für das Debuggen in der Entwicklungsphase geeignet sind und den Traffic in einer Produktionsumgebung nicht bewältigen können. Bei der Bereitstellung in einer Produktionsumgebung muss die Webanwendung hinter einem Webserver laufen. Gängige Webserver sind Gunicorn und uWSGI. Der Webserver bietet Optionen für die Parallelverarbeitung, wie z. B. Prozessmodelle und Threadmodelle, um die Parallelverarbeitungsleistung der Webanwendung zu verbessern.
In dem oben genannten einfachen Szenario gibt es vier Kombinationen von technischen Entscheidungen: Gunicorn + Django, Gunicorn + Flask, uWSGI + Django und uWSGI + Flask. Wenn jede Kombination erfordert, dass das Webanwendungs-Framework unterschiedliche Webdienst-Anpassungscodes bereitstellt, erreicht die Komplexität $N^2$, was offensichtlich nicht kosteneffektiv ist. Die Existenz von WSGI dient dazu, die Schnittstelle zwischen dem Webserver und der Webanwendung zu definieren, und Framework-Entwickler müssen nur für diese Schnittstelle programmieren. Auf diese Weise haben Webanwendungsentwickler mehr Freiheit bei der Wahl. Zum Beispiel kann derselbe Django-Code sowohl auf Gunicorn als auch auf uWSGI laufen.
Ohne ein Webanwendungs-Framework
Bevor wir erörtern, wie Django und Flask sich an WSGI anpassen, wollen wir das Problem zunächst vereinfachen. Die Rolle eines Web-Frameworks ist es, einige bequeme Funktionen wie Routing und HTTP-Request-Parsing bereitzustellen, um uns zu helfen, Webanwendungen einfacher und schneller zu entwickeln. Aber für sehr einfache Anwendungen können wir auch wählen, kein Framework zu verwenden.
Die von PEP definierte WSGI-Schnittstelle ist sehr einfach, und es ist nicht notwendig (und sollte auch nicht) irgendein Web-Framework zu verwenden:
HELLO_WORLD = b"Hello world!\n" def simple_app(environ, start_response): """Simplest possible application object""" status = '200 OK' response_headers = [('Content-type', 'text/plain')] start_response(status, response_headers) return [HELLO_WORLD]
Diese einfache Webanwendung interagiert mit dem Webserver über das environ
Umgebungsvariablen-Dictionary und die start_response
Funktion, und der Webserver stellt sicher, dass die korrekten Parameter übergeben werden.
Angenommen, der obige Code wird als app.py
gespeichert und Gunicorn wurde installiert. Sie können die Anwendung mit dem folgenden Befehl starten:
gunicorn app:simple_app
Standardmäßig bindet Gunicorn an Port 8000. Wir können curl
verwenden, um Anfragen zum Testen zu senden:
$ curl http://localhost:8000 Hello world!
Wie wir sehen können, funktioniert alles wie erwartet. Gleichzeitig ist die Codelogik dieser Webanwendung sehr einfach. Sie berücksichtigt nicht den Request-Pfad (wie /
, /api
, etc.) und die Request-Methode (wie GET, POST, PUT, etc.), und gibt immer einen Statuscode von 200 und Hello World!
als Response Body zurück.
$ curl http://localhost:8080/not-found Hello world! $ curl -X POST http://localhost:8080 Hello world!
Jenseits von Hello World
Wie bereits erwähnt, hat eine normale Webanwendung in der Regel mehrere Endpunkte und es wird erwartet, dass sie unterschiedliche Antworten auf unterschiedliche Anfragen zurückgibt.
Der Webserver speichert alle Informationen der Anfrage im environ
Dictionary, und es wird auch andere Umgebungsvariablen enthalten. Unter allen Schlüsseln müssen wir besonders auf die folgenden drei achten:
REQUEST_METHOD
: Die Request-Methode, wie z.B. GET, POST, etc.PATH_INFO
: Der Request-Pfad.wsgi.input
: Ein File-Objekt. Wenn der Request Body Daten enthält, können diese über dieses Objekt gelesen werden. Ein weiterer SchlüsselCONTENT_LENGTH
gibt die Länge des Request Bodys an, und die beiden werden normalerweise zusammen verwendet.
Angenommen, wir wollen eine neue POST-Schnittstelle auf dem /
Pfad implementieren, die JSON-artige Parameter empfängt. Wenn der Benutzer {"name": "xxx"}
übergibt, gibt die Webanwendung Hello, xxx!
zurück, während die GET-Schnittstelle unverändert bleibt und weiterhin Hello, World!
zurückgibt. Der Code ist wie folgt:
import json def simple_app(environ, start_response): request_method = environ["REQUEST_METHOD"] path_info = environ["PATH_INFO"] response_headers = [('Content-type', 'text/plain')] if path_info == '/': status = '200 OK' if request_method == 'GET': body = b'Hello world!\n' elif request_method == 'POST': request_body_size = int(environ["CONTENT_LENGTH"]) request_body = environ["wsgi.input"].read(request_body_size) payload = json.loads(request_body) name = payload.get("name", "") body = f"Hello {name}!\n".encode("utf-8") else: status = '405 Method Not Allowed' body = b'Method Not Allowed!\n' else: status = '404 NOT FOUND' body = b'Not Found!\n' start_response(status, response_headers) return [body]
Zusätzlich zur Behandlung des Request-Pfads und der Request-Methode haben wir auch einige einfache Client-Fehlererkennungen hinzugefügt. Zum Beispiel gibt der Zugriff auf einen anderen Pfad als /
einen 404 zurück, und der Zugriff auf /
mit einer anderen Methode als GET oder POST gibt einen 405 zurück. Hier sind einige einfache Tests:
$ curl http://localhost:8080/ Hello World! $ curl -X POST http://localhost:8080/ -d '{"name": "leapcell"}' Hello leapcell! $ curl -X PUT http://localhost:8080/ Method Not Allowed! $ curl http://localhost:8080/not-found Not Found!
Mehr wie Flask werden
Da die Logik der Webanwendung komplexer wird, wird die simple_app
Funktion immer länger. Diese Art von "Spaghetti-Code" entspricht offensichtlich nicht den guten Programmierpraktiken. Wir können uns auf die API von Flask für eine einfache Kapselung beziehen.
Konvertieren Sie zum Beispiel die Funktion in eine aufrufbare Klasse, so dass Webanwendungsentwickler die WSGI-Anwendung erhalten können; verwenden Sie routes
, um alle Zuordnungen von Pfaden zu Handler-Funktionen zu speichern; kapseln Sie environ
in ein request
Objekt, usw.
class MyWebFramework: def __init__(self): self.routes = {} def route(self, path): def wrapper(handler): self.routes[path] = handler return handler return wrapper def __call__(self, environ, start_response): request = self.assemble_request(environ) path_info = environ["PATH_INFO"] if path_info in self.routes: handler = self.routes[path_info] return handler(request) else: status = '404 NOT FOUND' response_headers = [('Content-type', 'text/plain')] start_response(status, response_headers) return [b'Not Found!\n'] app = MyWebFramework() @app.route("/my_endpoint") def my_endpoint_handler(request): # business logic here to handle request and assemble response response_headers = [('Content-type', 'text/plain')] status = '200 OK' body = b'Endpoint response!\n' return [body]
Auf diese Weise kann der MyWebFramework
Teil nach und nach zu einem Webanwendungs-Framework abstrahiert werden, und die eigentliche Business-Logik der Webanwendung muss nur jede Handler-Funktion schreiben. In Anlehnung an den Quellcode von flask.app.Flask
verwendet er ebenfalls eine ähnliche Implementierungsmethode. Eine Flask-Anwendung wird von der Flask
Kernklasse abgeleitet, und diese Klasse selbst ist eine WSGI-Anwendung.
Das Design von Django ist etwas anders. Es hat das ASGI (Asynchronous Server Gateway Interface) Protokoll vorgeschlagen und implementiert, um asynchrone Anfragen zu unterstützen. Eine Django-Anwendung kann durch interne Funktionen in eine ASGI-Anwendung oder eine WSGI-Anwendung umgewandelt werden. Wenn wir uns nur auf den WSGI-Teil konzentrieren, werden wir feststellen, dass sein Prinzip ähnlich dem ist, was zuvor vorgestellt wurde.
Empfohlene Lektüre
Leapcell: Das Beste vom Serverless Web Hosting
Abschließend möchte ich die beste Plattform für die Bereitstellung von Python-Diensten empfehlen: Leapcell
🚀 Erstellen Sie mit Ihrer Lieblingssprache
Entwickeln Sie mühelos in JavaScript, Python, Go oder Rust.
🌍 Stellen Sie unbegrenzt Projekte kostenlos bereit
Zahlen Sie nur für das, was Sie nutzen – keine Anfragen, keine Gebühren.
⚡ Pay-as-You-Go, keine versteckten Kosten
Keine Gebühren für Inaktivität, nur nahtlose Skalierbarkeit.
📖 Entdecken Sie unsere Dokumentation
🔹 Folgen Sie uns auf Twitter: @LeapcellHQ