Middleware
Starlette bevat verschillende middleware klassen voor het toevoegen van gedrag dat geldt voor de gehele applicatie. Deze zijn geïmplementeerd als standaard ASGI middleware klassen en kunnen worden toegepast op Starlette of een andere ASGI applicatie.
Middleware gebruiken
Met de Starlette-toepassingsklasse kunt u ASGI-middleware opnemen op een manier die ervoor zorgt dat deze altijd wordt verpakt door uitzonderingshandlers.
Starlette.applicaties importeren vanuit Starlette
Middleware importeren vanuit starlette.middleware
Vanaf starlette.middleware.htpsredirect import HTTPSRedirectMiddleware
Vanaf starlette.middleware.trustedhost importeren TrustedHostMiddleware
Routes =...
# Zorg ervoor dat alle verzoeken een example.com 'of
# '*. example.com' host header, en strikt http-only toegang af te dwingen.
Tussenwerk = [
Tussenwerk (
TrustedHostMiddleware,
toegestane _ hosts = ['example.com', '*. example.com'],
),
Middleware (HTTPSRedirectMiddleware)
]
App = Starlette (routes = routes, middleware=middleware)
Standaard bevat elke Starlette-applicatie automatisch twee stukken middleware:
ServerErrorMiddleware- Zorgt ervoor dat toepassingsuitzonderingen aangepaste 500 pagina 's kunnen retourneren of traceerinformatie voor de toepassing in DEBUG-modus kunnen weergeven. Dit is altijd de buitenste middlewarelaag.ExceptionMiddleware- Voeg uitzonderingshandlers toe, zodat specifieke soorten verwachte uitzonderingen kunnen worden geassocieerd met handlerfuncties. Als u bijvoorbeeldHTTPException(status_code=404)binnen een eindpunt verhoogt, wordt uiteindelijk een aangepaste 404-pagina weergegeven.
Middleware wordt van boven naar beneden geëvalueerd, dus in onze voorbeeldtoepassing zou de uitvoeringsstroom er als volgt uitzien:
- middleware
ServerErrorMiddlewareTrustedHostMiddlewareHTTPSRedirectMiddlewareExceptionMiddleware
- routing
- eindpunt
De volgende middleware-implementaties zijn beschikbaar in het Starlette-pakket:
CORS Middenwerk
Voeg geschikte CORS-headers toe aan uitgaande reacties om cross-origin-verzoeken van browsers mogelijk te maken.
De standaardparameters die worden gebruikt door CORSMiddleware-implementaties zijn standaard beperkend, dus u moet expliciet specifieke bronnen, methoden of kopteksten inschakelen, zodat browsers ze mogen gebruiken in cross-origin-contexten.
Starlette.applicaties importeren vanuit Starlette
Middleware importeren vanuit starlette.middleware
CORSMiddleware importeren vanuit starlette.middleware.cors
Routes =...
Tussenwerk = [
Middleware (CORSMiddleware, allow _ origins = ['*'])
]
App = Starlette (routes = routes, middleware=middleware)
De volgende argumenten werden gesteund:
allow_origins- Lijst van bronnen die toestemming moeten krijgen om cross-origineaanvragen te doen. Bijvoorbeeld['https://example.org', 'https://www.example.org']. Je kunt['*']gebruiken om elke bron toe te staan.allow_origin_regex- Een string voor reguliere expressies die overeenkomt met de bronnen die toestemming zouden moeten krijgen om cross-origineverzoeken te doen. Bijvoorbeeld:'https://.*\.example\.org'.allow_methods- Een lijst met HTTP-methoden die moeten worden toegestaan voor cross-origin-verzoeken. De standaard is['GET']. U kunt['*']gebruiken om alle standaardmethoden toe te staan.allow_headers- Een lijst met HTTP-verzoekkoppen die moeten worden ondersteund voor cross-origin-verzoeken. Standaard is[]. U kunt['*']gebruiken om alle headers toe te staan. Voor CORS-verzoeken zijn deAccept-,Accept-Language-,Content-Language- enContent-Type-headers altijd toegestaan.allow_credentials- geeft aan dat cookies voor cross-origin-verzoeken moeten worden ondersteund. De standaard isFalse. Om referenties toe te staan, kunnenallow_origins,allow_methodsenallow_headersniet worden ingesteld op['*'], ze moeten allemaal expliciet worden gespecificeerd.expose_headers- Geeft eventuele antwoordkoppen aan die toegankelijk moeten zijn voor de browser. Standaard is[].max_age- Stelt de maximale tijd in seconden in voor de browser om CORS-reacties in de cache op te slaan. Standaard600.
Middleware reageert op twee specifieke typen HTTP-verzoeken...
Cross-Origin Resource Sharing (CORS) Precheck-aanvraag
Dit zijn alle OPTIONS-verzoeken met Origin- en Access-Control-Request-Method-headers. In dit geval zal de middleware inkomende verzoeken onderscheppen en reageren met de juiste CORS-headers, evenals een 200 of 400-antwoord voor informatieve doeleinden.
eenvoudig verzoek
Elk verzoek met een Origin-header. In dit geval zal de middleware het verzoek zoals gewoonlijk doorgeven, maar zal de juiste CORS-header in het antwoord opnemen.
gesprek middleware
Voeg HTTP-sessies toe op basis van handtekeningcookies. Sessie-informatie is leesbaar maar niet aanpasbaar.
Gebruik de request.session-woordenboekinterface om sessiegegevens te openen of te wijzigen.
De volgende argumenten werden gesteund:
secret_key- Moet een willekeurige string zijn.session_cookieDe standaardwaarde is "gesprek".max_age- vervaltijd van de sessie in seconden. Standaard is 2 weken. Indien ingesteld opNone, is de geldige periode van de cookie hetzelfde als de duur van de browsersessie. De vlag*same_site- SameSite voorkomt dat de browser sessiecookies verzendt tijdens cross-site verzoeken. De standaard is'lax'.path- Pad ingesteld voor sessie cookies. Standaard is'/'.https_only- Geeft aan dat er een beveiligingsvlag moet worden ingesteld (alleen voor gebruik met HTTPS). Standaard isFalse...-
domain- Cookie-domein dat wordt gebruikt om cookies te delen tussen subdomeinen of tussen domeinen. Browsers stellen het domein standaard in op dezelfde host waar de cookie is ingesteld, met uitzondering van subdomeinen (referentie).Starlette.applicaties importeren vanuit Starlette Middleware importeren vanuit starlette.middleware Vanaf starlette.middleware.sessies importeren SessionMiddleware
Routes =...
Tussenwerk = [ Middleware (SessionMiddleware, secret _ key =..., https _ only = Waar) ]
App = Starlette (routes = routes, middleware=middleware)
HTTPS omleiding middleware
Mandaat dat alle inkomende verzoeken https of wss moeten zijn. Alle inkomende verzoeken aan http of ws worden doorgestuurd naar het beveiligingsschema.
Starlette.applicaties importeren vanuit Starlette
Middleware importeren vanuit starlette.middleware
Vanaf starlette.middleware.htpsredirect import HTTPSRedirectMiddleware
Routes =...
Tussenwerk = [
Middleware (HTTPSRedirectMiddleware)
]
App = Starlette (routes = routes, middleware=middleware)
Er zijn geen configuratie-opties voor deze middleware-klasse.
Vertrouwde host middleware
Forceer alle inkomende verzoeken om de juiste set Host-headers te hebben om te beschermen tegen HTTP-hostheaderaanvallen.
Starlette.applicaties importeren vanuit Starlette
Middleware importeren vanuit starlette.middleware
Vanaf starlette.middleware.trustedhost importeren TrustedHostMiddleware
Routes =...
Tussenwerk = [
Middleware (TrustedHostMiddleware_ hosts = ['example.com', '*. example.com'])
]
App = Starlette (routes = routes, middleware=middleware)
De volgende argumenten werden gesteund:
allowed_hosts- Lijst met domeinen die als hostnamen moeten worden toegestaan. Wildcard-domeinen zoals*.example.comkunnen worden gebruikt om subdomeinen te matchen. Om elke hostnaam toe te staan, gebruikt uallowed_hosts=["*"]of laat u middleware weg.www_redirect- Indien ingesteld op Waar worden aanvragen voor niet-www versies van toegestane hosts doorgestuurd naar hun www tegenhangers. Standaard isTrue.
Als het inkomende verzoek niet goed is gevalideerd, wordt een 400-antwoord verzonden.
GZip Middleware kopen?
Behandelt het GZip-antwoord voor elk verzoek dat "gzip" in de Accept-Encoding-header bevat.
Middleware verwerkt zowel standaard- als streamingreacties.
Starlette.applicaties importeren vanuit Starlette
Middleware importeren vanuit starlette.middleware
Vanaf starlette.middleware.gzip importeren GZipMiddleware
Routes =...
Tussenwerk = [
Middleware (GZipMiddleware, minimum _ size = 1000, compresslevel = 9)
]
App = Starlette (routes = routes, middleware=middleware)
De volgende argumenten werden gesteund:
minimum_size- GZip niet voor reacties kleiner dan deze minimale bytegrootte. De standaard is500.compresslevel- gebruikt tijdens GZip-compressie. Het is een geheel getal van 1 tot 9. De standaardwaarde is9. Hoe lager de waarde, hoe sneller de compressie, maar hoe groter de bestandsgrootte; hoe hoger de waarde, hoe langzamer de compressie, maar hoe kleiner de bestandsgrootte.
Middleware geeft geen GZip-reacties die Content-Encoding al hebben ingesteld om te voorkomen dat ze tweemaal worden gecodeerd.
BaseHTTP middleware
Een abstracte klasse waarmee u ASGI-middleware kunt schrijven voor de verzoek / antwoordinterface.
gebruik
Om een middleware-klasse te implementeren met BaseHTTPMiddleware, moet u de async def dispatch(request, call_next)-methode overschrijven.
Starlette.applicaties importeren vanuit Starlette
Middleware importeren vanuit starlette.middleware
Vanaf starlette.middleware.base importeren BaseHTTPMiddleware
Klasse CustomHeaderMiddleware (BaseHTTPMiddleware):
Aync def dispatch (zelf, verzoek, call _ next):
Reactie = afwachten call _ next (verzoek)
Response.headers ['Aangepast'] = 'Voorbeeld'
Geef reactie terug
Routes =...
Tussenwerk = [
Middleware (CustomHeaderMiddleware)
]
App = Starlette (routes = routes, middleware=middleware)
Als u configuratieopties voor middleware-klassen wilt bieden, moet u de __init__-methode overschrijven om ervoor te zorgen dat het eerste argument app is en dat alle resterende argumenten optionele zoekwoordargumenten zijn. Als u dat doet, zorg er dan voor dat u de app-eigenschap op de instantie instelt.
Klasse CustomHeaderMiddleware (BaseHTTPMiddleware):
Def _ _ init _ _ (zelf, app, header _ value = 'Voorbeeld'):
Super (). _ _ het _ _ (app)
Self.header _ waarde = header _ waarde
Aync def dispatch (zelf, verzoek, call _ next):
Reactie = afwachten call _ next (verzoek)
Response.headers ['Aangepast'] = zelf.header _ waarde
Geef reactie terug
Tussenwerk = [
Middleware (CustomHeaderMiddleware, header _ value = 'Aangepast')
]
App = Starlette (routes = routes, middleware=middleware)
Middleware-klassen mogen hun status niet wijzigen buiten de __init__-methode. In plaats daarvan moet u elke lokale staat aan de dispatch-methode overlaten of deze expliciet doorgeven, in plaats van de status van de middleware-instantie te wijzigen.
beperking
Momenteel heeft BaseHTTPMiddleware enkele bekende beperkingen:
- Het gebruik van
BaseHTTPMiddlewarevoorkomt dat wijzigingen incontextlib.ContextVarzich naar boven voortplanten. Dat wil zeggen, als u een waarde voorContextVarin een eindpunt instelt en probeert deze uit een relais te lezen, zult u zien dat de waarde verschilt van wat u in het eindpunt instelt (zie deze test voor een voorbeeld van dit gedrag).
Gebruik pure ASGI-middleware om deze beperkingen te overwinnen, zoals hieronder weergegeven.
Zuivere ASGI-middenstukken
De ASGI-specificatie maakt het mogelijk om ASGI-middleware rechtstreeks te implementeren met behulp van de ASGI-interface, als een reeks ASGI-applicaties, waarbij de volgende op zijn beurt wordt aangeroepen. In feite is dit de manier waarop de middleware-klassen die met Starlette worden geleverd, worden geïmplementeerd.
Deze benadering op een lager niveau biedt meer controle over gedrag en verbetert de interoperabiliteit tussen frameworks en servers. Het overwint ook de beperkingen van BaseHTTPMiddleware.
Schrijven van pure ASGI middleware
De meest gebruikelijke manier om ASGI-middleware te maken, is door een klasse te gebruiken.
Klasse ASGIMiddleware:
Def _ _ init _ _ (zelf, app):
self.app = app
Aync def _ _ call _ _ (zelf, bereik, ontvangen, verzenden):
Wacht self.app (scope, ontvangen, verzenden)
De bovenstaande middleware is de meest elementaire ASGI-middleware. Het neemt een ouder ASGI-applicatie als parameter in zijn constructor en implementeert een async __call__-methode die de bovenliggende applicatie aanroept.
Sommige implementaties, zoals asgi-cors, gebruiken een alternatieve stijl, met functies:
Functools importeren
Gebruik asgi _ middleware ():
Vergelijk asgi _ decorator (app):
@ functools.wraps (app)
Aync def wrap _ app (bereik, ontvangen, verzenden):
Wacht app (scope, ontvangen, verzenden)
Gewikkelde _ app terugsturen
Retourneren asgi _ decorator
ASGI-middleware moet echter een opvraagbaar object zijn dat drie parameters accepteert:scope,receive en send.
scopeis een woordenboek dat informatie bevat over verbindingen, waarscope["type"]kan zijn:"http": Gebruikt voor HTTP-verzoeken."websocket": Gebruikt voor WebSocket verbindingen."lifespan": Voor ASGI-levenscyclusberichten.
receiveensendkunnen worden gebruikt om ASGI-gebeurtenisberichten uit te wisselen met een ASGI-server - meer hierover hieronder. Het type en de inhoud van deze berichten is afhankelijk van het type scope. Meer informatie in de ASGI-specificatie.
Gebruik van pure ASGI middleware
Pure ASGI middleware kan net als elke andere middleware worden gebruikt.
Starlette.applicaties importeren vanuit Starlette
Middleware importeren vanuit starlette.middleware
Vanaf middleware importeren ASGIMiddleware
Routes =...
Tussenwerk = [
Middleware (ASGIMiddleware),
]
Uitgever: App = Starlette (..., middleware=middleware)
Zie ook Middleware gebruiken.
typ annotatie
Er zijn twee manieren om middleware te annoteren: Starlette zelf of asgiref gebruiken.
-
Starlette gebruiken: geschikt voor de meest voorkomende use-cases.
Van starlette.types importeren ASGIApp, Bericht, Toepassingsgebied, Ontvangen, Verzenden
Klasse ASGIMiddleware: Def _ _ init _ _ (zelf, app: ASGIApp) - > Geen: self.app = app
Async def _ _ call _ _ (zelf, scope: Scope, ontvangen: ontvangen, verzenden: verzenden) - > Geen: Als scope ["type"]! = "http": Retourneren self.app (scope, ontvangen, verzenden) Async def send _ wrapper (bericht: Bericht) - > Geen: #... Doe maar wat In afwachting van verzending (bericht) Wacht self.app (bereik, ontvangen, verzenden _ wrapper) -
gebruikt
asgiref: om strengere typehints te bereiken.Van asgiref.typing importeren ASGI3Application, ASGIReceiveCallable, ASGISendCallable, toepassingsgebied Van asgiref.typing importeren ASGIReceiveEvent, ASGISendEvent
Klasse ASGIMiddleware: Def _ _ init _ _ (zelf, app: ASGI3Application) - > Geen: self.app = app
Async def _ _ call _ _ (zelf, scope: Scope, ontvangen: ASGIReceiveCallable, verzenden: ASGISendCallable) - > Geen: Als scope ["type"]! = "http": Wacht self.app (scope, ontvangen, verzenden) Terugkeer Async def send _ wrapper (bericht: ASGISendEvent) - > Geen: #... Doe maar wat In afwachting van verzending (bericht) Retourneren self.app (bereik, ontvangen, verzenden _ wrapper)
gemeenschappelijk patroon
Behandel alleen bepaalde verzoeken
ASGI middleware kan specifiek gedrag toepassen op basis van de inhoud van de scope.
Als u bijvoorbeeld alleen HTTP-verzoeken wilt verwerken, schrijft u...
Klasse ASGIMiddleware:
Def _ _ init _ _ (zelf, app):
self.app = app
Aync def _ _ call _ _ (zelf, bereik, ontvangen, verzenden):
Als scope ["type"]! = "http":
Wacht self.app (scope, ontvangen, verzenden)
Terugkeer
# Doe hier iets!
Wacht self.app (scope, ontvangen, verzenden)
Evenzo is alleen WebSocket-middleware beschermd op scope["type"] != "websocket".
Middleware kan zich ook anders gedragen, afhankelijk van de aanvraagmethode, URL, header, enzovoort.
Multiplexen van Starlette-componenten
Starlette biedt verschillende gegevensstructuren die ASGI scope,receive en / of send parameters accepteren, waardoor u op een hoger abstractieniveau kunt werken. Dergelijke gegevensstructuren omvatten Request,Headers,QueryParams,URL, enzovoort.
U kunt bijvoorbeeld een Request instantiëren om HTTP-verzoeken gemakkelijker te controleren.
Van starlette. aanvragen import aanvragen
Klasse ASGIMiddleware:
Def _ _ init _ _ (zelf, app):
self.app = app
Aync def _ _ call _ _ (zelf, bereik, ontvangen, verzenden):
Als scope ["type"] = = "http":
Aanvraag = Aanvraag (scope)
... # Gebruik `request.method`,`request.url`,`request.headers`, enz.
Wacht self.app (scope, ontvangen, verzenden)
U kunt ook reacties hergebruiken, die ook ASGI-toepassingen zijn.
Stuur een gretige reactie
Aansluiting controleren scope Hiermee kunt u voorwaardelijk verschillende ASGI-applicaties aanroepen. Een use-case kan zijn om een antwoord te sturen zonder de applicatie te bellen.
Deze middleware gebruikt bijvoorbeeld een woordenboek om een permanente omleiding uit te voeren op basis van het gevraagde pad. Als u het routerings-URL-patroon moet aanpassen, kan dit worden gebruikt om doorlopende ondersteuning voor oudere URL 's te implementeren.
URL geïmporteerd uit starlette.datastructuren
RedirectResponse geïmporteerd uit starlette.reacties
Klasse omleidingenMiddleware:
Def _ _ init _ _ (zelf, app, pad _ mapping: dict):
self.app = app
Zelf.pad _ mapping = pad _ mapping
Aync def _ _ call _ _ (zelf, bereik, ontvangen, verzenden):
Als scope ["type"]! = "http":
Wacht self.app (scope, ontvangen, verzenden)
Terugkeer
URL = URL (scope = scope)
Als url.path in zelf. path _ mapping:
Url = url. vervangen (pad = self.path _ mapping [url.path])
Reactie = RedirectResponse (url, status _ code = 301)
In afwachting van reactie (scope, ontvangen, verzenden)
Terugkeer
Wacht self.app (scope, ontvangen, verzenden)
Het voorbeeldgebruik zou er als volgt uitzien:
Starlette.applicaties importeren vanuit Starlette
Middleware importeren vanuit starlette.middleware
Routes =...
Omleidingen = {
"/ v1 / resource /": "/ v2 / resource /",
# ...
}
Tussenwerk = [
Middleware (OmleidingMiddleware, pad _ mapping=redirections),
]
App = Starlette (routes = routes, middleware=middleware)
Aanvraag controleren of wijzigen
Verzoekinformatie kan worden geopend of gewijzigd door op scope te werken. Voor een volledig voorbeeld van dit patroon, zie Uvicorn 's ProxyHeadersMiddleware, die scope controleert en aanpast wanneer het achter een front-end proxy wordt geserveerd.
Bovendien kunt u door het receive ASGI-oproepbare object in te pakken de HTTP-aanvraagtekst openen of wijzigen door het http.request ASGI-gebeurtenisbericht te manipuleren.
Deze middleware berekent en registreert bijvoorbeeld de grootte van de inkomende aanvraagtekst...
Klasse LoggedRequestBodySizeMiddleware:
Def _ _ init _ _ (zelf, app):
self.app = app
Aync def _ _ call _ _ (zelf, bereik, ontvangen, verzenden):
Als scope ["type"]! = "http":
Wacht self.app (scope, ontvangen, verzenden)
Terugkeer
lichaamsgrootte = 0
Async def ontvangen _ loggen _ verzoek _ lichaam _ grootte ():
Niet-lokale lichaamsgrootte
Bericht = afwachten ontvangen ()
Bevestig bericht ["type"] = = "htp.request"
body _ size + = len (bericht.get ("lichaam", b "))
Zo niet message.get ("more _ body", False):
Afdrukken (f "Grootte van de inhoud van het verzoek was:{body_size}bytes")
Bericht terugsturen
Wacht self.app (scope, ontvang _ logging _ request _ body _ size, verzend)
Evenzo kan de WebSocket-middleware de websocket.receive ASGI-gebeurtenisberichten manipuleren om inkomende WebSocket-gegevens te inspecteren of te wijzigen.
Zie msgpack-asgi voor een voorbeeld van het wijzigen van de hoofdtekst van een HTTP-verzoek.
Controleer of wijzig de reactie
Door de send ASGI callable in te pakken, kunt u de HTTP-reactie van de onderliggende applicatie inspecteren of wijzigen. Reageer hiervoor op de http.response.start- of http.response.body ASGI-gebeurtenisberichten.
Deze middleware voegt bijvoorbeeld enkele vaste extra antwoordkoppen toe:
MutableHeaders importeren vanuit starlette.datastructuren
Klasse ExtraResponseHeadersMiddleware:
Def _ _ init _ _ (zelf, app, headers):
self.app = app
Self.headers = kopteksten
Aync def _ _ call _ _ (zelf, bereik, ontvangen, verzenden):
Als scope ["type"]! = "http":
Retourneren self.app (scope, ontvangen, verzenden)
Async def send _ with _ extra _ headers (bericht):
Als bericht ["type"] = = "htp.response.start":
Headers = MutableHeaders (scope = bericht)
Voor sleutels, waarden in self.headers:
Headers.append (sleutel, waarde)
In afwachting van verzending (bericht)
Wacht self.app (bereik, ontvangen, verzenden _ met _ extra _ headers)
Zie ook asgi-logger, dat een voorbeeld heeft van het controleren van HTTP-reacties en het loggen van configureerbare HTTP-toegangslogregels.
Evenzo kan WebSocket-middleware de websocket.send ASGI-gebeurtenisberichten manipuleren om uitgaande WebSocket-gegevens te inspecteren of te wijzigen.
Houd er rekening mee dat als u de antwoordtekst wijzigt, u de Content-Length-header van de respons moet bijwerken om overeen te komen met de nieuwe lichaamslengte van de respons. Zie brotli-asgi voor een volledig voorbeeld.
Informatie doorgeven aan het eindpunt
Als u informatie moet delen met de onderliggende applicatie of het eindpunt, kunt u deze opslaan in het scope-woordenboek. Merk op dat dit een conventie is - Starlette gebruikt deze methode bijvoorbeeld om routeringsinformatie te delen met eindpunten - maar het maakt geen deel uit van de ASGI-specificatie.
Als u dat doet, zorg er dan voor dat u sleutels gebruikt die waarschijnlijk niet door andere middleware of applicaties worden gebruikt om conflicten te voorkomen.
Een eindpunt heeft bijvoorbeeld toegang tot request.scope["asgi_transaction_id"] wanneer de volgende middleware wordt meegeleverd.
Uid importeren
Klasse TransactionIDMiddleware:
Def _ _ init _ _ (zelf, app):
self.app = app
Aync def _ _ call _ _ (zelf, bereik, ontvangen, verzenden):
Toepassingsgebied ["asgi _ transactie _ id"] = uuid.uuid4 ()
Wacht self.app (scope, ontvangen, verzenden)
Schoonmaak en foutafhandeling
U kunt uw toepassing in een try/except/finally-blok of contextmanager verpakken voor opschoning of foutafhandeling.
De volgende middleware kan bijvoorbeeld statistieken verzamelen en uitzonderingen op toepassingen afhandelen...
Import tijd
Klasse MonitoringMiddleware:
Def _ _ init _ _ (zelf, app):
self.app = app
Aync def _ _ call _ _ (zelf, bereik, ontvangen, verzenden):
Start = tijd.tijd ()
Probeer:
Wacht self.app (scope, ontvangen, verzenden)
Behalve uitzondering als exc:
... # Verwerk de uitzondering
Verhogen
Eindelijk:
Einde = tijd.tijd ()
Verlopen = einde - begin
... # Submit `elapsed` als metriek naar een monitoring backend
Raadpleeg ook timing-asgi voor een compleet voorbeeld van dit patroon.
Potentiële problemen
ASGI middleware zou staatloos moeten zijn
Aangezien ASGI is ontworpen om gelijktijdige verzoeken af te handelen, moet elke verbindingsspecifieke status worden beperkt tot __call__ Binnen het bereik van de implementatie. Als u dit niet doet, resulteert dit meestal in variabele lees- / schrijfbotsingen tussen verzoeken en zullen er waarschijnlijk fouten optreden.
Als er bijvoorbeeld een X-Mock-header in de respons aanwezig is, vervangt deze bewerking voorwaardelijk de responslichaam...
✅ doe maar
```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)
```
❌ Nee hoor.
```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)
```
Raadpleeg ook GZipMiddleware voor een volledige voorbeeldimplementatie die dit potentiële probleem aanpakt.
Verder lezen
Dit document zou voldoende moeten zijn als een goede basis voor het maken van ASGI-middleware.
Er zijn echter veel uitstekende artikelen over dit onderwerp:
- Inleiding tot ASGI: de opkomst van het asynchrone Python-netwerkecosysteem
- Hoe ASGI Middleware te schrijven
Middleware gebruiken in andere frameworks
Om ASGI-middleware rond andere ASGI-toepassingen te wikkelen, moet u een algemener patroon gebruiken voor het inpakken van applicatie-instanties:
App = TrustedHostMiddleware (app, toegestane _ hosts = ['example.com'])
Je kunt dit ook doen met een Starlette-applicatie-instantie, maar het is beter om de middleware=<List of Middleware instances>-stijl te gebruiken omdat deze:
- zorgt ervoor dat alles is verpakt in een buitenste laag
ServerErrorMiddleware. - behoudt de
app-instantie op het hoogste niveau.
Middleware toepassen op routeringsgroepen
Middleware kan ook worden toegevoegd aan een Mount-instantie, waarmee u middleware kunt toepassen op een set routerings- of subtoepassingen.
Starlette.applicaties importeren vanuit Starlette
Middleware importeren vanuit starlette.middleware
Vanaf starlette.middleware.gzip importeren GZipMiddleware
Van starlette. routing importeren Mount, Route
Routes = [
Monteren (
"/",
Routes = [
Route (
"/ voorbeeld",
Eindpunt =...,
)
],
Middleware = [Tussenproducten (GZipMiddleware)]
)
]
App = Starlette (routes = routes)
Houd er rekening mee dat de middleware die op deze manier wordt gebruikt, niet is verpakt in middleware met uitzondering, zoals de middleware die wordt toegepast op Starlette-toepassingen.
Dit is meestal geen probleem omdat het alleen w**oor het controleren of wijzigen van middleware voor Response, en zelfs dan wilt u deze logica waarschijnlijk niet toepassen op foutreacties. Als u middleware-logica alleen op bepaalde routes op foutreacties wilt toepassen, zijn er een paar opties:
- Voeg een
ExceptionMiddlewaretoe opMount - voegt een
try/except-blok toe aan uw middleware en retourneert daar een foutreactie - splitst tagging en verwerking in twee middleware, één geplaatst op
Mountdie het antwoord markeert als verwerking vereist (bijvoorbeeld doorscope["log-response"] = Truein te stellen), en de andere toegepast op deStarlette-applicatie om het zware werk te doen.
De Route/WebSocket-klassen accepteren ook een middleware-parameter waarmee u middleware op één enkele route kunt toepassen:
Starlette.applicaties importeren vanuit Starlette
Middleware importeren vanuit starlette.middleware
Vanaf starlette.middleware.gzip importeren GZipMiddleware
Van starlette. routing importeren Route
Routes = [
Route (
"/ voorbeeld",
Eindpunt =...,
Middleware = [Tussenproducten (GZipMiddleware)]
)
]
App = Starlette (routes = routes)
U kunt ook middleware toepassen op de Router-klasse, waarmee u middleware kunt toepassen op een reeks routes:
Starlette.applicaties importeren vanuit Starlette
Middleware importeren vanuit starlette.middleware
Vanaf starlette.middleware.gzip importeren GZipMiddleware
Van starlette. routing importeren Route, Router
Routes = [
Route ("/ voorbeeld", endpoint =...),
Route ("/ een andere", eindpunt =...),
]
Router = Router (routes = routes, middleware = [Middleware (GZipMiddleware)])
middleware van derden
Toevoegen aan github
Deze middleware voegt authenticatie toe aan elke ASGI-applicatie, waarbij gebruikers moeten inloggen met hun GitHub-account (via OAuth). Toegang kan worden beperkt tot specifieke gebruikers of leden van een specifieke GitHub-organisatie of -team.
agi-csrf
Middleware voor bescherming tegen CSRF-aanvallen. Deze middleware implementeert een double-commit cookie-modus waarin een cookie wordt ingesteld en vervolgens wordt vergeleken met een csrftoken verborgen formulierveld of een x-csrftoken HTTP-header.
Middleware schrijven
Een direct alternatief voor de sessie-middleware van Starlette, met behulp van de JWT-module van Authlib.
Bugsnag middleware kopen?
Een middleware-klasse voor het loggen van uitzonderingen op Bugsnag.
CSRF Middenwaren
Middleware om te beschermen tegen CSRF-aanvallen. Deze middleware implementeert een double-commit cookie-modus waarin een cookie wordt ingesteld en vervolgens wordt vergeleken met een x-csrftoken HTTP-header.
Middleware voor vroege gegevens
Middleware en decorateurs voor het detecteren en weigeren van eerdere TLSv1.3-gegevensverzoeken.
Prometheus middleware kopen?
Een middleware-klasse voor het vastleggen van Prometheus-statistieken met betrekking tot verzoeken en reacties, inclusief lopende verzoeken, tijden, enz...
middleware voor proxy header
Uvicorn bevat een middleware-klasse voor het bepalen van IP-adressen aan clientzijde op basis van de X-Forwarded-Proto- en X-Forwarded-For-headers bij gebruik van een proxyserver. Voor complexere proxyconfiguraties moet u deze middleware mogelijk aanpassen.
snelheid beperkende middleware
Een snelheidsbeperkende middleware. Reguliere expressie matching URL 's; flexibele regels; zeer aanpasbaar. Zeer eenvoudig te gebruiken.
Middleware aanvragen
Een middleware-klasse voor het lezen / genereren van verzoek-ID 's en deze aan het toepassingslogboek te koppelen.
Middleware met rolbeugel
Een middleware-klasse voor het loggen van uitzonderingen, fouten en logberichten naar Rollbar.
StarletteOpentracing
Een middleware-klasse die trackinginformatie naar OpenTracing.io-compatibele trackers stuurt en kan worden gebruikt om gedistribueerde applicaties te analyseren en te bewaken.
Beveiliging Cookie Middleware
Aanpasbare middleware voor het toevoegen van automatische cookie-encryptie en decodering aan Starlette-applicaties, die extra ondersteuning biedt voor bestaande cookie-gebaseerde middleware.
timing middleware
Een middleware-klasse die timinginformatie (CPU-tijd en wandkloktijd) uitzendt voor elk verzoek dat er doorheen gaat. Bevat een voorbeeld van hoe deze timings als statsd-statistieken kunnen worden uitgezonden.
WSGIMiddleware
Een middleware-klasse die verantwoordelijk is voor het converteren van WSGI-applicaties naar ASGI-applicaties.