Middleware
Starlette enthält mehrere Middleware-Klassen zum Hinzufügen von Verhaltensweisen, die für die gesamte Anwendung gelten, die als Standard-ASGI-Middleware-Klassen implementiert sind und auf Starlette oder eine andere ASGI-Anwendung angewendet werden können.
Verwendung von Zwischenräumen
Mit der Starlette-Anwendungsklasse können Sie ASGI-Middleware so einschließen, dass sichergestellt ist, dass sie immer von Ausnahmehandlern eingepackt wird.
von starlette. applications import Starlette
von starlette. midleware import Middleware
von starlette. middleware. httpsredirect import HTTPSRedirectMiddleware
from starlette. middleware. trustedhost import TrustedHostMiddleware
Die Routen….
#Ensure that all requests include an 'example.com' or #Ensure that all requests include an 'example.com' or #Ensure that all requests include an 'example.com' or #Ensure that all requests include an 'example.com' or
#''. example.com''host header, and strictly enforce https-only access.
Mittelfeld []
Die Midlife-Funktion (
bei TrustedHostMiddleware,
allowed_hosts ='example.com','*. example.com'], und
),
Middleware (HTTPSRedirectMiddleware) oder
]
Starlette (routes = routes, middleware = middleware) ist die Abkürzung für "routes".
Standardmäßig enthält jede Starlette-Anwendung automatisch zwei Middleware-Abschnitte:
ServerErrorMiddleware-Stellt sicher, dass Anwendungsausnahmen benutzerdefinierte 500-Seiten zurückgeben oder Tracking-Informationen für die Anwendung im DEBUG-Modus anzeigen können, der immer die äußerste Middleware-Schicht ist.ExceptionMiddleware-Fügen Sie Exception-Handler hinzu, so dass ein bestimmter Typ von erwarteten Ausnahmen einer Handlerfunktion zugeordnet werden kann, z. B. führt das Auslösen vonHTTPException(status_code=404)innerhalb eines Endpunkts zu einer benutzerdefinierten 404-Seite.
Middleware wird von oben nach unten bewertet, so dass der Ausführungsprozess in unserer Beispielanwendung wie folgt aussehen würde:
- Das Mittelstück
ServerErrorMiddlewareTrustedHostMiddlewareHTTPSRedirectMiddlewareExceptionMiddleware
- Route wählen.
- Endhaltestelle
In Starlette-Paketen können die folgenden Middleware verwendet werden:
CORS Zwischenablage
Fügen Sie den entsprechenden CORS-Header für ausgehende Antworten hinzu, um Cross-Origin-Anfragen von Browsern zu ermöglichen.
Die von der CORSIddleware-Implementierung verwendeten Standardparameter sind standardmäßig restriktiv, daher müssen Sie bestimmte Quellen, Methoden oder Header explizit aktivieren, damit Browser sie in einem domänenübergreifenden Kontext verwenden können.
von starlette. applications import Starlette
von starlette. middleware import Middleware
von starlette. middleware. cors import CORSMiddleware
Die Routen….
Mittelfeld []
Middleware (CORSMiddleware, allow_origins = Hochhaus '*'])
]
Starlette (routes = routes, middleware = middleware) ist die Abkürzung für "routes".
Folgende Argumente wurden unterstützt:
allow_origins- Eine Liste von Quellen, die Cross-Source-Anforderungen zulassen sollten, z. B.['https://example.org', 'https://www.example.org']Sie können es verwenden.['*']Erlaubt jede Quelle.allow_origin_regex-Eine Zeichenfolge für einen regulären Ausdruck, die mit einer Quelle übereinstimmt, die Cross-Source-Anfragen ausführen soll, z. B.'https://.*\.example\.org'.allow_methods- Eine Liste der HTTP-Methoden, die für Cross-Origin-Anforderungen zugelassen sein sollten, wird standardmäßig angezeigt.['GET']Sie können es verwenden.['*']Alle Standardmethoden sind erlaubt.allow_headers- Eine Liste von HTTP-Anforderungsheadern, die für Cross-Origin-Anforderungen unterstützt werden sollen, ist standardmäßig aktiviert.[]Sie können verwenden.['*']um alle Header für CORS-Anfragen zu erlauben.Accept、Accept-Language、Content-LanguageundContent-TypeKopfbedeckung ist immer erlaubt.allow_credentials- Cookies, die angeben, dass Cross Origin Requests unterstützt werden sollen, werden standardmäßig verwendet.FalseZusätzlich zu den Belegen,allow_origins、allow_methodsundallow_headersKann nicht eingerichtet werden für['*']Und sie alle müssen klar definiert werden.expose_headers-Gibt an, dass alle Antwortheader, die dem Browser zugänglich gemacht werden sollen, standardmäßig[]sind.max_age-Die Standardeinstellung für die maximale Zeit, die der Browser zum Caching von CORS-Antworten in Sekunden benötigt, ist600.
Middleware antwortet auf zwei bestimmte Arten von HTTP-Anforderungen…
Domainübergreifende gemeinsame Nutzung von Ressourcen (CORS) Preflight-Anforderungen
Dies sind alle OPTIONS-Anforderungen mit Origin-und Access-Control-Request-Method-Headern In diesem Fall fängt die Middleware die eingehende Anforderung ab und antwortet mit den entsprechenden CORS-Headern sowie den 200-oder 400-Antworten zu Informationszwecken.
Eine einfache Forderung
Jede trägt Origin In diesem Fall leitet die Middleware die Anforderung wie gewohnt weiter, enthält jedoch den entsprechenden CORS-Header in der Antwort.
Mitten im Gespräch
Fügen Sie HTTP-Sitzungsinformationen hinzu, die auf signierten Cookies basieren, die lesbar, aber nicht änderbar sind.
Verwenden Sie die request.session Dictionary Interface für den Zugriff auf oder die Änderung von Sitzungsdaten.
Folgende Argumente wurden unterstützt:
secret_key- Es muss ein zufälliger String sein.session_cookie- Der Standardwert ist "Gespräch".max_age-Sitzungsablaufzeit in Sekunden Der Standardwert ist 2 Wochen Wenn Sie aufNonesetzen, ist das Cookie für die gleiche Dauer wie die Browsersitzung gültig. Das*same_site-SameSite Flag verhindert, dass Browser bei Cross-Site-Anfragen Sitzungscookies senden, wobei der Standardwert'lax'ist.path-Der Standardpfad, der für Sitzungscookies festgelegt wird, ist'/'.https_only- Gibt an, dass Sicherheitsflaggen gesetzt werden sollten (nur in Verbindung mit HTTPS verfügbar).False。-
domain-Cookie-Domäne, die zum Teilen von Cookies zwischen Subdomains oder Domänen verwendet wird Der Browser legt standardmäßig die Domäne auf demselben Host fest, auf dem Cookies gesetzt sind, mit Ausnahme der Subdomain (Referenz).von starlette. applications import Starlette von starlette. middleware import Middleware from starlette. middleware. sessions import sessionMiddleware (engl. für „ Starlette. Middleware. Sitzungen importieren ")
Die Routen…
Mittelweg [] Middleware (sessionMiddleware, secret_key =..., https_only = True)(Seite 2) ]
Starlette (routes = routes, middleware = middleware) ist die Abkürzung für "routes".
HTTPS-Redirection-Middleware aufrufen
Alle eingehenden Anfragen müssen https oder wss sein und alle an http oder ws übergebenen Anfragen werden an das sichere Programm weitergeleitet.
von starlette. applications import Starlette
von starlette. midleware import Middleware
von starlette. middleware. httpsredirect import HTTPSRedirectMiddleware
Die Routen…
Mittelweg []
Middleware (HTTPSRedirectMiddleware) oder
]
Starlette (routes = routes, middleware = middleware) ist die Abkürzung für "routes".
Für diese Middlewareklasse gibt es keine Konfigurationsoptionen.
Vertrauenswürdige Mittelsmänner
Erzwingt, dass alle eingehenden Anforderungen über einen ordnungsgemäß festgelegten Host-Header verfügen, um HTTP-Host-Header-Angriffe zu verhindern.
von starlette. applications import Starlette
von starlette. middleware import Middleware
from starlette. middleware. trustedhost import TrustedHostMiddleware
Die Routen…
Mittelweg []
Middleware (TrustedHostMiddleware, allowed_hosts = VMware 'beispiel.com','*. beispiel.com'])
]
Starlette (routes = routes, middleware = middleware) ist die Abkürzung für "routes".
Folgende Argumente wurden unterstützt:
allowed_hosts- Eine Liste von Domänennamen, die als Hostnamen zulässig sein sollten, wie z. B.*.example.comSolche Platzhalter-Domänennamen können verwendet werden, um Subdomains abzugleichen Um einen beliebigen Hostnamen zu ermöglichen, können Sie verwenden.allowed_hosts=["*"]Oder man lässt die Mitte weg.www_redirect-Wenn auf True gesetzt, werden Anfragen an nicht-www-Versionen von zulässigen Hosts an ihre www-Version umgeleitet, die standardmäßigTrueist.
Wenn eine eingehende Anforderung nicht ordnungsgemäß überprüft wird, wird eine 400-Antwort gesendet.
GZip-Zwischenlösungen
Verarbeitet die GZip-Antwort für jede Anfrage, die "gzip" im Accept-Encoding-Header enthält.
Die Middleware verarbeitet sowohl Standardantworten als auch Stream-Antworten.
von starlette. applications import Starlette
von starlette. midleware import Middleware
from starlette. middleware. gzip import GZipMiddleware (englisch)
Die Routen…
Mittelweg []
Middleware (GZipMiddleware, minimum_size = 1000 und compresslevel = 9)
]
Starlette (routes = routes, middleware = middleware) ist die Abkürzung für "routes".
Folgende Argumente wurden unterstützt:
minimum_size- Bei Antworten, die kleiner als diese minimale Bytegröße sind, führen Sie keine GZip-Komprimierung durch.500。compresslevel- Wird während der GZip-Komprimierung verwendet, ist es eine ganze Zahl von 1 bis 9, die standardmäßig verwendet wird.9Je niedriger der Wert, desto schneller ist die Komprimierung, aber je größer die Dateigröße ist; je höher der Wert, desto langsamer die Komprimierung, aber desto kleiner die Dateigröße.
Die Middleware komprimiert keine GZip-Responses, die bereits auf Content-Encoding gesetzt sind, um zu verhindern, dass sie zweimal decodiert werden
BaseHTTP-Zwischenspeicher
Eine abstrakte Klasse, mit der Sie ASGI-Middleware für eine Anfrage-/Antwort-Schnittstelle schreiben können.
Die Verwendung von
Um eine Middleware-Klasse mit BaseHTTPMiddleware zu implementieren, müssen Sie die Methode async def dispatch(request, call_next) überschreiben.
von starlette. applications import Starlette
von starlette. middleware import Middleware
from starlette. middleware. base import BaseHTTPIddleware {f}
class CustomHeaderMiddleware (BaseHTTPIddleware):
async def dispatch (self, request, call_next):(für den Suchbegriff)
request = await call_next (Anforderung)
response. headers 'Custom']=' Beispiel '
return antwort zurück
Die Routen….
Mittelweg []
Middleware (CustomHeaderMiddleware) Bearbeiten
]
Starlette (routes = routes, middleware = middleware) ist die Abkürzung für "routes".
Wenn Sie Konfigurationsoptionen für Middleware-Klassen bereitstellen möchten, sollten Sie sie neu schreiben. __init__ Stellen Sie sicher, dass der erste Parameter app Alle übrigen Parameter sind optionale Schlüsselwortparameter, wenn Sie dies tun, stellen Sie sicher, dass Sie sie auf der Instanz festlegen. app Eigenschaften.
class CustomHeaderMiddleware (BaseHTTPIddleware):
def__init__(self, app, header_value ='Example'):
super ().__init__(für app)
selbst. header_value = header_value
async def dispatch (self, request, call_next):(für den Dispatch)
request = await call_next (Anforderung)
response . headers ' Custom'] = self . header _ value [ Bearbeiten | Quelltext bearbeiten ]
return antwort zurück
Mittelweg [ ]
Middleware (CustomHeaderMiddleware , header _ value ='Customized') (Dateiendung)
]
Starlette (routes = routes , middleware = middleware) ist die Abkürzung für " routes " .
Eine Middleware-Klasse sollte ihren Status nicht außerhalb der __init__-Methode ändern , sondern Sie sollten jeden Zustand entweder lokal in der dispatch-Methode belassen oder explizit übergeben , ohne den Status der Middleware-Instanz zu ändern .
Beschränktheit
Derzeit, BaseHTTPMiddleware Es gibt einige bekannte Einschränkungen:
- verwendet
BaseHTTPMiddleware, um zu verhindern , dass Änderungen ancontextlib.ContextVarnach oben übertragen werden , d . h . wenn Sie einen Wert fürContextVarin Ihrem Endpunkt festlegen und versuchen , ihn aus dem Relay zu lesen , werden Sie feststellen , dass sich dieser Wert von dem unterscheidet , den Sie am Endpunkt festgelegt haben (ein Beispiel für dieses Verhalten finden Sie in diesem Test) .
Um diese Einschränkungen zu überwinden , verwenden Sie die reine ASGI-Middleware , wie unten gezeigt .
Reine ASGI-Middleware
Die ASGI-Spezifikation ermöglicht die Implementierung von ASGI-Middleware direkt über die ASGI-Schnittstelle als eine Reihe von ASGI-Anwendungen , die wiederum die nächste aufrufen , genau wie die Middleware-Klasse , die mit Starlette geliefert wird .
Dieser Low-Level-Ansatz bietet mehr Kontrolle über das Verhalten und verbessert die Interoperabilität zwischen Frameworks und Servern. BaseHTTPMiddleware deren Beschränkungen.
Reine ASGI-Middleware erstellen
Die häufigste Methode zum Erstellen von ASGI-Middleware ist die Verwendung einer Klasse .
Klasse ASGiMiddleware :
def _ _ init _ _ (self , app) : (für sich , app)
self.app = Die App
async def _ _ call _ _ (self , scope , receive , send) : async def _ _ call _ _ (self , scope , receive , send) und
Await sehenself.app(Offenbarung , Offenbarung) .
Die obige Middleware ist die grundlegendste ASGI-Middleware , die eine übergeordnete ASGI-Anwendung als Argument in ihrem Konstruktor erhält und eine async __call__-Methode implementiert , die diese übergeordnete Anwendung aufruft .
Einige Implementierungen , wie asgi-cors, verwenden einen alternativen Stil , der die Funktion verwendet :
Importieren von Funktionen
def asgi _ middleware () () () (Beispiel) :
def asgi _ decorator (für) :
@ functools. wraps (App)(Englisch)
async def wrapped_app (scope, receive, send):
Await App (Bildschirm, Empfänger, Senden)
zurück zu Wraped_App
Zurück zu ASGI_DECORATOR
In jedem Fall muss die ASGI-Middleware ein aufrufbares Objekt sein, das drei Parameter akzeptiert:scope,receive und send.
scopeist ein Wörterbuch, das Informationen über Verbindungen enthält, von denenscope["type"]:"http": Wird für HTTP-Anforderungen verwendet."websocket": für WebSocket-Verbindungen."lifespan": Wird für ASGI Lifecycle Messages verwendet.
receiveundsendASGI-Ereignisnachrichten können zum Austausch mit ASGI-Servern verwendet werden-weitere Informationen finden Sie in der ASGI-Spezifikation, in der Typ und Inhalt dieser Nachrichten weiter unten beschrieben werden.
Verwendung von reiner ASGI-Middleware
Reine ASGI-Middleware kann wie jede andere Middleware verwendet werden:
von starlette. applications import Starlette
von starlette. middleware import Middleware
from. middleware import ASGIIddleware importiert von. middleware
Die Routen…
Mittelweg []
Middleware (ASGiMiddleware) oder
]
app = Starlette (..., Mittelteil = Mittelteil)
Siehe auch die Verwendung von Zwischenräumen.
Typ Anmerkung
Es gibt zwei Möglichkeiten, der Middleware Anmerkungen hinzuzufügen: entweder Starlette selbst oder asgiref.
-
Mit Starlette: Für die meisten gängigen Anwendungsfälle.
from starlette. types import ASGIApp, Nachricht, Scope, Empfänger, Senden
Klasse ASGiMiddleware : def _ _ init _ _ (self , app : ASGIApp) - > Keine : self.app = Die App
async def _ _ call _ _ (self , scope : Scope , receive : Receive , send : Send) - > None : if scope [ " type " ] ! = " http " aus : return await zurückself.app(Offenbarung , Offenbarung) async def send _ wrapper (Nachricht : Nachricht) - > None : # etwas tun Nachricht (await send) Await sehenself.app(Weitergeleitet von Scope , receive , send _ wrapper) -
verwendet
asgiref: um strengere Typhinweise zu implementieren .typing import ASGI3Application , ASGIReceiveCallable , ASGISendCallable , Scope (Eingabeaufforderung) from asgiref . typing import ASGIReceiveEvent , ASGIEndEvent (englisch)
Klasse ASGIIddleware : def _ _ init _ _ (self , app : ASGI3Application) - > Keine : self.app = Die App
async def _ _ call _ _ (self , scope : Scope , receive : ASGIReceiveCallable , send : ASGIEndCallable) - > None : if scope [ " type " ] ! = " http " aus : Await sehenself.app(Offenbarung , Offenbarung) . return Zurück async def send _ wrapper (Nachricht : ASGIEndEvent) - > None : # etwas tun Nachricht (await send) return await zurückself.app(Weitergeleitet von Scope , receive , send _ wrapper)
Übliches Modell
Nur bestimmte Anforderungen bearbeiten
ASGI-Middleware ermöglicht die Anwendung spezifischer Verhaltensweisen basierend auf dem Inhalt von scope.
Wenn Sie zum Beispiel nur HTTP-Anfragen bearbeiten , schreiben Sie ...
Klasse ASGIIddleware :
def _ _ init _ _ (self , app) : (für sich , app)
self.app = Die App
async def _ _ call _ _ (self , scope , receive , send) : async def _ _ call _ _ (self , scope , receive , send) und
if scope [ " type " ] ! = " http " aus :
Await sehenself.app(Offenbarung , Offenbarung)
return Zurück
# Mach hier etwas !
Await istself.app(Offenbarung , Offenbarung)
Ebenso ist nur die Middleware für WebSockets auf scope["type"] != "websocket" geschützt .
Middleware kann sich auch je nach Anforderungsmethode , URL oder First-Class - Standard unterschiedlich verhalten .
Wiederherstellen von Starlette-Komponenten
Starlette bietet mehrere Datenstrukturen, die ASGI akzeptieren. scope 、 receive und/oder send Parameter, mit denen Sie auf einer höheren Abstraktionsstufe arbeiten können, umfassen solche Datenstrukturen. Request 、 Headers 、 QueryParams 、 URL Abwarten.
Beispielsweise können Sie ein Request instanziieren , um HTTP-Anforderungen einfacher überprüfen zu können :
from starlette . requests import Request (Eingabeaufforderung)
Klasse ASGIIddleware :
def _ _ init _ _ (self , app) : (Beispiel)
self.app = Die App
async def _ _ call _ _ (self , scope , receive , send) : async def _ _ call _ _ (self , scope , receive , send) und
if scope [ " type " ] = " http " : wenn Bereich [ " type " ] = " http " ist :
Request = Request (Vorschlag)
Verwenden Sie `request.method`,`request.url`,`request.headers`, etc.
Await istself.app(Offenbarung , Offenbarung)
Sie können auch Antworten wiederverwenden , bei denen es sich um ASGI-Apps handelt .
Eine eifrige Antwort schicken
Mit scope können Sie bedingt verschiedene ASGI-Anwendungen aufrufen - ein Anwendungsfall könnte darin bestehen , die Antwort zu senden , ohne die Anwendung aufzurufen .
Diese Middleware verwendet beispielsweise ein Wörterbuch , um eine dauerhafte Umleitung basierend auf dem Pfad der Anforderung durchzuführen , wenn Sie das Routing-URL - Muster neu gestalten müssen , was verwendet werden kann , um eine kontinuierliche Unterstützung für ältere URLs zu implementieren .
from starlette . datastructures import URL (englisch)
from starlette . responses import RedirectResponse (englisch)
Klasse RedirectsMiddleware :
def _ _ init _ _ (self , app , path _ mapping : dict) : def _ init _ _ _ (self , app , path _ mapping : dict) :
self.app = Die App
Siehe auch : path _ mapping = path _ mapping
async def _ _ call _ _ (self , scope , receive , send) : async def _ _ call _ _ (self , scope , receive , send) und
if scope [ " type " ] ! = " http " aus :
Await sehenself.app(Offenbarung , Offenbarung)
return Zurück
url = URL (Bereich = URL)
if url . path in self . path _ mapping : Wenn die URL . path in self . path _ mapping :
url = url . replace (path = self . path _ mapping [ url . path ]) [ Bearbeiten | Quelltext bearbeiten ]
response = RedirectResponse (url , status _ code = 301) Bearbeiten
Erhalte Antworten (Senden , Empfangen , Senden)
return Zurück
Await sehenself.app(Offenbarung , Offenbarung) .
Die Beispielverwendung sieht so aus :
von starlette . applications import Starlette
von starlette . middleware import Middleware
Die Routen … .
Redirections = {Vorlage : Redirections}
"/v1/resource/" : "/v2/resource/" und "/v2/resource/"
# ...
}
Mittelweg [ ]
Middleware (RedirectsMiddleware , path _ mapping = Redirections) und
]
Starlette (routes = routes , middleware = middleware) ist die Abkürzung für " routes " .
Überprüfen oder Ändern von Anforderungen
Ein vollständiges Beispiel dieses Musters kann durch die Operation scope aufgerufen oder geändert werden , siehe ProxyHeadersMiddleware von Uvicorn , das scope überprüft und anpasst , wenn Dienste hinter einem Front-End - Agent bereitgestellt werden .
Darüber hinaus ermöglicht das Verpacken von receive ASGI-aufrufbaren Objekten den Zugriff auf oder Ändern des HTTP-Anforderungstextes , indem Sie die http.request ASGI-Ereignismeldung bearbeiten .
Diese Middleware berechnet und protokolliert beispielsweise die Größe des Subjekts der eingehenden Anforderung …
class LoggedRequestBodySizeMiddleware :
def _ _ init _ _ (self , app) : (Beispiel)
self.app = Die App
async def _ _ call _ _ (self , scope , receive , send) : async def _ _ call _ _ (self , scope , receive , send) und
if scope [ " type " ] ! = " http " aus :
Await sehenself.app(Offenbarung , Offenbarung)
return Zurück
Größe = 0 _ Größe
async def receive _ logging _ request _ body _ size () () () : () (auf Englisch)
lokale Körpergröße {f}
Nachricht = await receive ()
assert message [ " type " ] = = " http . request " (Nachricht vom Typ)
body _ size + = len (message . get (" body " , " b ")) (Nachricht . get (" Körper " , " b "))
get (" more _ body " , False) :
Größe des angeforderten Körpers war :{body_size}-Bytes
return Botschaft
Await sehenself.app(request _ body _ size , senden)
In ähnlicher Weise kann die WebSocket-Middleware websocket.receive ASGI-Ereignismeldungen verarbeiten , um eingehende WebSocket-Daten zu überprüfen oder zu ändern .
Ein Beispiel für die Änderung des HTTP-Anforderungstextes finden Sie unter msgpack-asgi.
Antworten überprüfen oder ändern
Durch das Verpacken eines aufrufbaren send ASGI-Objekts können Sie die von der zugrunde liegenden Anwendung gesendeten HTTP-Antworten überprüfen oder ändern , indem Sie auf http.response.start- oder http.response.body ASGI-Ereignismeldungen reagieren .
Diese Middleware fügt beispielsweise einige feste zusätzliche Antwortheader hinzu :
from starlette . datastructures import MutableHeaders (Deutsche Übersetzung)
class ExtraResponseHeadersMiddleware :
def _ _ init _ _ (self , app , headers) (def _ _ init _ _ (self , app , headers) (für Benutzer) :
self.app Die App
self . headers = headers (engl . für Kopf)
async def _ _ call _ _ (self , scope , receive , send) : async def _ _ call _ _ (self , scope , receive , send) und
if scope [ " type " ] ! = " http " aus :
return await Zurückself.app(Offenbarung , Offenbarung) .
async def send _ with _ extra _ headers (Nachricht) :
if message [ " type " ] = = " http . response . start " :
headers = MutableHeaders (scope = Nachricht)
for key , value in self . headers für Schlüssel , Wert in sich selbst . headers :
headers . append (Schlüssel , Wert)
Nachricht (await send)
Await sehenself.app(Scope , Receive , send _ with _ extra _ headers) (Nachricht , Nachricht , Nachricht)
Siehe auch asgi-logger, das ein Beispiel zum Überprüfen von HTTP-Antworten und zum Aufzeichnen konfigurierbarer HTTP-Zugriffsprotokollzeilen enthält .
In ähnlicher Weise kann die WebSocket-Middleware die ASGI-Ereignismeldung websocket.send verarbeiten , um ausgehende WebSocket-Daten zu überprüfen oder zu ändern .
Wenn Sie den Antworttext ändern , müssen Sie den Antwort-Content-Length- Header aktualisieren , um ihn an die neue Länge des Antworttextes anzupassen , siehe brotli-asgi für ein vollständiges Beispiel .
Informationen bis zum Ende weitergeben
Wenn Sie Informationen mit der zugrunde liegenden Anwendung oder dem Endpunkt teilen müssen , können Sie sie in einem scope-Wörterbuch speichern Beachten Sie , dass dies eine Konvention ist - Starlette verwendet diese Methode zum Teilen von Routing-Informationen mit dem Endpunkt - aber es ist nicht Teil der ASGI-Spezifikation Wenn Sie dies tun , stellen Sie sicher , dass Sie Schlüssel verwenden , die wahrscheinlich nicht von anderen Middleware - oder Anwendungen verwendet werden , um Konflikte zu vermeiden .
Wenn beispielsweise die folgende Middleware enthalten ist , kann der Endpunkt auf request.scope["asgi_transaction_id"] zugreifen .
Der Import von UUUID
Klasse TransactionIDLeware :
def _ _ init _ _ (self , app) : (Beispiel)
self.app Die App
async def _ _ call _ _ (self , scope , receive , send) : async def _ _ call _ _ (self , scope , receive , send) und
scope [ " asgi _ transaction _ id " ] = uuid.uuid4 () oder
Await sehenself.app(Offenbarung , Offenbarung)
Reinigung und Fehlbehandlung
Sie können die Anwendung in einem try/except/finally-Block oder Kontext-Manager verpacken , um Reinigungs - oder Fehlerbehandlungen durchzuführen .
Beispielsweise kann die folgende Middleware Metriken erfassen und Anwendungsausnahmen behandeln …
Import Zeit
class MonitoringMiddleware :
def _ _ init _ _ (self , app) : (Beispiel)
self.app = Die App
async def _ _ call _ _ (self , scope , receive , send) : async def _ _ call _ _ (self , scope , receive , send) und
Zeit = Zeit . Zeit ()
versuchen :
Await istself.app(Offenbarung , Offenbarung) .
Ausnahme als exc :
# Prozess der Ausnahme
Raise aufziehen
Endlich :
Zeit = Zeit ()
elapsed = end-start (end-start) Bearbeiten
#Unterziehen `elapsed` Wie eine Metrik für ein Monitoring-Backend
Siehe auch timing-asgi für ein vollständiges Beispiel dieses Musters.
mögliche Probleme.
Die ASGI Middleware sollte zustandslos sein
Da ASGI gleichzeitige Anforderungen verarbeiten soll, sollte jeder verbindungsspezifische Status auf die __call__-Implementierung beschränkt werden, wenn dies nicht der Fall ist, was in der Regel zu requestübergreifenden Variablen-Lese-/Schreibkonflikten führt und höchstwahrscheinlich zu Fehlern.
Wenn z. B. der X-Mock-Header in der Antwort vorhanden ist, ersetzt dieser Vorgang den Antworttext bedingt.
» machen.
```python
from starlette.datastructures import Headers
class MockResponseBodyMiddleware:
def __init__(self, app, content):
self.app = app
self.content = content
async def __call__(self, scope, receive, send):
if scope["type"] != "http":
await self.app(scope, receive, send)
return
# A flag that we will turn `True` if the HTTP response
# has the 'X-Mock' header.
# ✅: Scoped to this function.
should_mock = False
async def maybe_send_with_mock_content(message):
nonlocal should_mock
if message["type"] == "http.response.start":
headers = Headers(raw=message["headers"])
should_mock = headers.get("X-Mock") == "1"
await send(message)
elif message["type"] == "http.response.body":
if should_mock:
message = {"type": "http.response.body", "body": self.content}
await send(message)
await self.app(scope, receive, maybe_send_with_mock_content)
```
» Nein
```python hl_lines="7-8"
from starlette.datastructures import Headers
class MockResponseBodyMiddleware:
def __init__(self, app, content):
self.app = app
self.content = content
# ❌: This variable would be read and written across requests!
self.should_mock = False
async def __call__(self, scope, receive, send):
if scope["type"] != "http":
await self.app(scope, receive, send)
return
async def maybe_send_with_mock_content(message):
if message["type"] == "http.response.start":
headers = Headers(raw=message["headers"])
self.should_mock = headers.get("X-Mock") == "1"
await send(message)
elif message["type"] == "http.response.body":
if self.should_mock:
message = {"type": "http.response.body", "body": self.content}
await send(message)
await self.app(scope, receive, maybe_send_with_mock_content)
```
Siehe auch GZipMiddleware für eine vollständige Beispielimplementierung, die dieses potenzielle Problem behebt.
weiter lesen
Dieses Dokument sollte als gute Grundlage für die Erstellung von ASGI-Middleware dienen.
Es gibt jedoch viele gute Artikel zum Thema:
- Einführung in ASGI: Die Entstehung eines asynchronen Python Network Ecosystems
- Wie schreibe ich ASGI Middleware
Middleware in anderen Frameworks verwenden
Um ASGI-Middleware um andere ASGI-Anwendungen herum zu verpacken, sollten Sie Anwendungsinstanzen mit einem allgemeineren Schema verpacken:
app = TrustedHostMiddleware (app, allowed_hosts ='beispiel.com'])
Sie können dies auch mit einer Starlette-Anwendungsinstanz tun, aber es ist besser, den middleware=<List of Middleware instances>-Stil zu verwenden, da er Folgendes bewirkt:
- sorgt dafür, dass alles in einer äußersten Schicht von
ServerErrorMiddlewareeingewickelt ist. - behält die Top-Level-Instanz von
appbei.
Anwenden der Middleware auf die Routing-Gruppe
Middleware kann auch einer Mount-Instanz hinzugefügt werden, wodurch Sie die Middleware auf eine Reihe von Routen oder Unteranwendungen anwenden können:
von starlette. applications import Starlette
von starlette. middleware import Middleware
von starlette. middleware. gzip import GZipMiddleware
Routing import Mount, Route von starlette.
Die Bahn […]
Der Berg (
"/",
Die Bahn […]
Der Weg (
"Beispiel",
Endpoint für…
)
],
middleware =[Middleware (GZipMiddleware)] oder
)
]
Starlette (Routen = Routen) Bearbeiten
Beachten Sie, dass die auf diese Weise verwendete Middleware nicht wie die auf die Starlette-Anwendung angewendete Middleware für die Ausnahmebehandlung verpackt ist, was im Allgemeinen kein Problem ist, da sie nur für die Überprüfung oder Änderung der Response-Middleware geeignet ist, und selbst dann möchten Sie diese Logik möglicherweise nicht auf die Fehlerantwort anwenden, wenn Sie die Middlewarelogik nur auf bestimmte Routen anwenden möchten, gibt es mehrere Optionen:
- fügt eine
ExceptionMiddlewarezuMounthinzu. - fügt einen
try/except-Block zu Ihrer Middleware hinzu und gibt von dort eine Fehlermeldung zurück - teilt das Markup und die Verarbeitung in zwei Middleware auf, eine auf
Mount, die die Antwort als verarbeitet markiert, wie sie benötigt wird (z. B. durch das Festlegen vonscope["log-response"] = True), und die andere aufStarlette-Anwendungen, um die Schwerstarbeit zu erledigen.
Die Route/WebSocket-Klasse akzeptiert auch einen middleware-Parameter, mit dem Sie die Middleware auf eine einzige Route anwenden können:
von starlette. applications import Starlette
von starlette. midleware import Middleware
von starlette. middleware. gzip import GZipMiddleware
von starlette. routing import Route
Die Bahn […]
Der Weg (
"Beispiel",
Endpoint für…
middleware =[Middleware (GZipMiddleware)] oder
)
]
Starlette (Routen = Routen) Bearbeiten
Sie können Middleware auch auf die Router-Klasse anwenden, wodurch Sie die Middleware auf eine Reihe von Routen anwenden können:
von starlette. applications import Starlette
von starlette. midleware import Middleware
von starlette. middleware. gzip import GZipMiddleware
von starlette. routing import route, Router
Die Bahn […]
Route ("/beispiel", endpoint =...),
Route ("/another", endpoint =...), oder
]
Router = Router (Router = Routen, Middleware =[Middleware (GZipMiddleware)])
Drittmittelpunkt
Auth-Github (englisch)
Diese Middleware fügt Authentifizierung für jede ASGI-Anwendung hinzu, bei der Benutzer sich mit ihrem GitHub-Konto (über OAuth) anmelden müssen, und der Zugriff kann auf einen bestimmten Benutzer oder auf Mitglieder einer bestimmten GitHub-Organisation oder-Team beschränkt sein.
Csrf und Asgi-CSRF
Die Middleware zum Schutz vor CSRF-Angriffen implementiert einen Zwei-Wege-Cookie-Modus, in dem ein Cookie gesetzt wird und dann ein Formularfeld mit csrftoken ausgeblendet wird. x-csrftoken HTTP-Header zum Vergleichen.
Authlib für Zwischenprodukte
Ein direkter Ersatz für die Starlette-Sitzungs-Middleware, die das jwt-Modul von authlib verwendet.
Bugsnag Mittelteil
Eine Middleware-Klasse zum Protokollieren von Ausnahmen in Bugsmag.
CSRF-Middleware für
Die Middleware zum Schutz vor CSRF-Angriffen implementiert ein Zwei-Wege-Cookie-Muster, in dem ein Cookie gesetzt und dann mit einem x-csrftoken-HTTP-Header verglichen wird.
Frühzeitige Daten-Middleware
Middleware und Dekoratoren zum Erkennen und Ablehnen von früheren Datenanfragen nach TLSv1.3.
Prometheus Mittelteil
Eine Middleware-Klasse zum Erfassen von Prometheus-Metriken in Bezug auf Anforderungen und Antworten, einschließlich laufender Anforderungen, Zeiten usw.
Der Agenten-Mittelsmann .
Uvicorn enthält eine Middleware-Klasse zur Bestimmung der Client-IP - Adresse auf der Grundlage der X-Forwarded-Proto- und X-Forwarded-For-Header bei der Verwendung eines Proxyservers , die Sie möglicherweise anpassen müssen , um eine komplexere Proxykonfiguration zu erstellen .
Geschwindigkeitsbegrenzungs-Middleware
Eine Middleware mit Geschwindigkeitsbegrenzungen für reguläre Ausdrücke , die mit URLs übereinstimmt ; flexible Regeln ; sehr anpassbar und sehr einfach zu bedienen .
Geforderte mittlere
Middleware-Klasse zum Lesen/Generieren der Anforderungs-ID und Anhängen an das Anwendungsprotokoll .
Rollbar-Zwischenlösungen
Eine Middleware-Klasse zum Protokollieren von Ausnahmen , Fehlern und Protokollnachrichten in der Rollbar .
StarletteOpentracing Bearbeiten
Eine Art Mittelweg , mit demOpenTracing.ioEin kompatibler Tracker sendet Tracking-Informationen und kann zur Analyse und Überwachung verteilter Anwendungen verwendet werden .
Sichere Cookie-Middleware
Anpassbare Middleware zum Hinzufügen der automatischen Cookie-Verschlüsselung und - Entschlüsselung zu den Starlette-Anwendungen , die zusätzliche Unterstützung für bestehende cookiebasierte Middleware bietet .
Zeitliche Zwischentöne
Eine Middleware-Klasse , die Timing-Informationen für jede Anforderung ausgibt , die sie durchläuft (CPU-Zeit und Wandelzeit) , enthält Beispiele dafür , wie diese Timings als Statsd-Metriken ausgegeben werden können .
mit WSGIIddleware
Eine Middleware-Klasse , die für die Konvertierung einer WSGI-Anwendung in eine ASGI-Anwendung verantwortlich ist .