Aller au contenu

Middleware

Starlette contient plusieurs classes middleware pour ajouter des comportements qui s'appliquent à l'ensemble de l'application. ceux-ci sont implémentés en tant que classes middleware ASGI standard et peuvent être appliqués à Starlette ou à toute autre application ASGI.

Utilisation du middleware

La classe d'application Starlette vous permet d'inclure le middleware ASGI d'une manière qui garantit qu 'il est toujours enveloppé dans un gestionnaire d'exception.

de starlette.applications import Starlette
de starlette.middleware import Middleware
de starlette.middleware.httpsredirect import HTTPSRedirectMiddleware
de starlette.middleware.trustedhost import TrustedHostMiddleware

routes = ...

# Ensure que toutes les demandes incluent un 'example.com' ou
# '*.example.com' host header, et strictement enforce https-only access.
middleware = [
    Middleware(
        TrustedHostMiddleware,
        allowed_hosts=['example.com','*.example.com'],
    ),
    Middleware(HTTPSRedirectMiddleware)
]

app = Starlette(routes=routes, middleware=middleware)

Par défaut, chaque application Starlette inclut automatiquement deux segments de middleware:

  • ServerErrorMiddleware-Assurez-vous que les exceptions d'application peuvent renvoyer une page 500 personnalisée ou afficher les informations de suivi de l'application en mode DEBUG.
  • ExceptionMiddleware-Ajoute un gestionnaire d'exception afin qu 'un type particulier de situation d'exception attendue puisse être associé à une fonction de gestionnaire, par exemple, le déclenchement d'un HTTPException(status_code=404) à l'intérieur d'un point de terminaison finira par rendre une page 404 personnalisée.

Le middleware est évalué de haut en bas, donc dans notre exemple d'application, le processus d'exécution ressemblerait à ceci:

  • Le middleware
    • ServerErrorMiddleware
    • TrustedHostMiddleware
    • HTTPSRedirectMiddleware
    • ExceptionMiddleware
  • Sélection de route
  • Endpoint à

Les middlewares suivants peuvent être implémentés dans le pack Starlette:

Le middleware de CORS

Ajoutez un en-tête CORS approprié aux réponses envoyées vers l'extérieur pour permettre les demandes inter-sources des navigateurs.

Les paramètres par défaut utilisés par l'implémentation CORSMiddleware sont restrictifs par défaut, vous devez donc activer explicitement des sources, des méthodes ou des en-têtes spécifiques afin que les navigateurs soient autorisés à les utiliser dans un contexte inter-domaines.

de starlette.applications import Starlette
de starlette.middleware import Middleware
de starlette.middleware.cors import CORSMiddleware

routes = ...

middleware = [
    Middleware(CORSMiddleware, allow_origins=['*'])
]

app = Starlette(routes=routes, middleware=middleware)

Les arguments suivants ont été soutenus:

  • allow_origins-Liste des sources qui devraient être autorisées à faire des demandes inter-sources. par exemple ['https://example.org', 'https://www.example.org']. vous pouvez utiliser ['*'] pour autoriser n'importe quelle source.
  • allow_origin_regex-Une chaîne d'expression régulière utilisée pour faire correspondre les sources qui devraient être autorisées à faire des demandes inter-sources. exemple:'https://.*\.example\.org'.
  • allow_methods - Une liste des méthodes HTTP qui devraient être autorisées pour les requêtes inter-sources. par défaut ['GET'] Vous pouvez utiliser le ['*'] pour permettre toutes les méthodes standard.
  • allow_headers - Une liste des en-têtes de requête HTTP qui devraient être pris en charge pour les requêtes inter-sources. [] Vous pouvez utiliser le ['*'] pour permettre tous les en-têtes. pour les demandes CORS, Accept 、 Accept-Language 、 Content-Language et Content-Type Les en-têtes sont toujours autorisés.
  • allow_credentials - Cookie indiquant que les demandes inter-sources doivent être prises en charge. par défaut False En outre, pour permettre le certificat, allow_origins 、 allow_methods et de allow_headers ne peut être fixé à ['*'] Ils doivent tous être explicitement désignés.
  • expose_headers-Indique tout en-tête de réponse qui devrait être rendu accessible au navigateur.[] est par défaut.
  • max_age - Définit le temps maximum en secondes pour que le navigateur cache la réponse CORS. 600 。

Le middleware répond à deux types spécifiques de requêtes HTTP:

Requêtes de pré-contrôle pour le partage des ressources interdomaines (CORS)

Il s'agit de toute demande OPTIONS avec les en-têtes Origin et Access-Control-Request-Method. Dans ce cas, le middleware interceptera la demande entrante et répondra avec l'en-tête CORS approprié, ainsi qu 'une réponse 200 ou 400 à des fins d'information.

Une simple demande

Toute demande avec un en-tête Origin. Dans ce cas, le middleware passera la demande comme d'habitude, mais inclura l'en-tête CORS approprié dans la réponse.

Le middleware sessionnel

Ajout d'une session HTTP basée sur un Cookie signé Les informations de session sont lisibles mais non modifiables.

Utilisez l'interface du dictionnaire request.session pour accéder aux données de session ou les modifier.

Les arguments suivants sont soutenus:

  • secret_key - Ce devrait être une chaîne aléatoire.
  • session_cookie - La valeur par défaut est "Session".
  • max_age-Durée d'expiration de la session en secondes. par défaut 2 semaines. si elle est définie sur None, le Cookie aura la même durée de vie que la session du navigateur.
  • same_site-Le drapeau SameSite empêche les navigateurs d'envoyer des cookies de session lors de demandes intersites.'lax' est la valeur par défaut.
  • path-chemin défini pour les cookies de session.'/' est par défaut.
  • https_only-Indique que le drapeau de sécurité doit être défini (utilisable uniquement avec HTTPS).False est par défaut.
  • domain - Cookie Domaine utilisé pour partager des cookies entre sous-domaines ou entre domaines. le navigateur définit le domaine par défaut sur le même hôte qui a défini le Cookie, à l'exclusion des sous-domaines (références).

    de starlette.applications import Starlette de starlette.middleware import Middleware de starlette.middleware.sessions import SessionMiddleware

    routes = ...

    middleware = [ Middleware(SessionMiddleware, secret_key=..., https_only=True) ]

    app = Starlette(routes=routes, middleware=middleware)

Redirection du middleware HTTPS

Impose que toutes les requêtes entrantes soient https ou wss Toute requête entrante vers http ou ws sera redirigée vers le schéma de sécurité.

de starlette.applications import Starlette
de starlette.middleware import Middleware
de starlette.middleware.httpsredirect import HTTPSRedirectMiddleware

Routes = ...

middleware = [
    Middleware(HTTPSRedirectMiddleware)
]

app = Starlette(routes=routes, middleware=middleware)

Pour cette classe middleware, il n'y a pas d'option de configuration.

Middleware pour Trusted Host

Impose que toutes les requêtes entrantes aient un en-tête Host correctement configuré pour se protéger contre les attaques d'en-tête hôte HTTP.

de starlette.applications import Starlette
de starlette.middleware import Middleware
de starlette.middleware.trustedhost import TrustedHostMiddleware

Routes = ...

middleware = [
    Middleware(TrustedHostMiddleware, allowed_hosts=['example.com','*.example.com'])
]

app = Starlette(routes=routes, middleware=middleware)

Les arguments suivants ont été soutenus:

  • allowed_hosts-Une liste de noms de domaine qui devraient être autorisés comme noms d'hôte. les noms de domaine génériques tels que *.example.com peuvent être utilisés pour correspondre aux sous-domaines. pour autoriser tout nom d'hôte, utilisez allowed_hosts=["*"] ou omettez le middleware.
  • www_redirect-Si elle est définie sur True, les requêtes pour autoriser une version non www d'un hôte seront redirigées vers sa version www correspondante.True par défaut.

Si la demande entrante n'est pas correctement validée, une réponse 400 sera envoyée.

GZip Middleware pour GZip

Gérer les réponses GZip pour toute demande contenant "gzip" dans l'en-tête Accept-Encoding.

Le middleware traitera les réponses standard et les réponses de flux.

de starlette.applications import Starlette
de starlette.middleware import Middleware
from starlette.middleware.gzip import GZipMiddleware


Routes = ...

middleware = [
    Middleware(GZipMiddleware, minimum_size=1000, compresslevel=9)
]

app = Starlette(routes=routes, middleware=middleware)

Les arguments suivants ont été soutenus:

  • minimum_size-Ne pas compresser GZip pour les réponses inférieures à cette taille minimale d'octets.500 est la valeur par défaut.
  • compresslevel-Utilisé pendant la compression GZip. c'est un entier de 1 à 9. la valeur par défaut est 9. plus la valeur est basse, plus la compression est rapide, mais plus la taille du fichier est grande; plus la valeur est élevée, plus la compression est lente, mais la taille du fichier est petite.

Le middleware n'effectue pas de compression GZip sur les réponses pour lesquelles Content-Encoding a été configuré, afin d'éviter qu 'elles ne soient encodées deux fois.

Le middleware BaseHTTP

Une classe abstraite qui vous permet d'écrire un middleware ASGI pour une interface requête/réponse.

Utilisation de la situation

Pour implémenter une classe middleware avec BaseHTTPMiddleware, vous devez réécrire la méthode async def dispatch(request, call_next).

de starlette.applications import Starlette
de starlette.middleware import Middleware
de starlette.middleware.base import BaseHTTPMiddleware


Classe CustomHeaderMiddleware(BaseHTTPMidleware):
    async def dispatch(self, request, call_next):
        response = await call_next(demande)
        response.headers ['Custom'] = 'Exemple'
        Retour Réponse

Routes = ...

middleware = [
    Middleware(CustomHeaderMiddleware)
]

app = Starlette(routes=routes, middleware=middleware)

Si vous souhaitez donner des options de configuration à une classe middleware, vous devez réécrire __init__ méthode, en s'assurant que le premier paramètre est app , tous les autres paramètres sont des paramètres de mots-clés facultatifs. si vous le faites, assurez-vous de les définir sur votre instance. app propriétés.

Classe CustomHeaderMiddleware(BaseHTTPMidleware):
    def __init__(self, app, header_value ='Exemple'):
        super().__init__(app)
        self.header_value = header_value

    async def dispatch(self, request, call_next):
        response = await call_next(demande)
        response.headers [`Custom '] = self.header_value
        Retour Réponse


middleware = [
    Middleware(CustomHeaderMiddleware, header_value ="Customized")
]

app = Starlette(routes=routes, middleware=middleware)

Une classe middleware ne devrait pas modifier son état en dehors de la méthode __init__. au lieu de cela, vous devriez laisser tout état local à la méthode dispatch ou le passer explicitement, plutôt que de modifier l'état de l'instance middleware.

Limitation de la

Actuellement,BaseHTTPMiddleware a quelques limitations connues:

  • L'utilisation de BaseHTTPMiddleware empêchera les modifications apportées à contextlib.ContextVar de se propager vers le haut. c'est-à-dire que si vous définissez une valeur pour ContextVar dans un point final et que vous essayez de la lire à partir d'un métaware, vous constaterez que la valeur est différente de celle que vous avez définie dans le point final (voir ce test pour un exemple de ce comportement).

Pour surmonter ces limitations, utilisez un middleware ASGI pur, comme indiqué ci-dessous.

Le middleware ASGI pur

La spécification ASGI permet d'implémenter directement un middleware ASGI en utilisant l'interface ASGI, comme une série d'applications ASGI qui appellent successivement la suivante-en fait, la classe middleware fournie avec Starlette est implémentée de cette façon.

Cette approche de niveau inférieur offre un plus grand contrôle sur le comportement et améliore l'interopérabilité entre les frameworks et les serveurs. il surmonte également les limites de BaseHTTPMiddleware.

Écrire du middleware ASGI pur

La façon la plus courante de créer un middleware ASGI consiste à utiliser une classe.

Classe ASGIMiddleware:
    def __init__(self, app):
        self.app = application

    async def __call__(self, scope, receive, send):
        await self.app (scope, receive, send)

Le middleware ci-dessus est le middleware ASGI le plus basique. il reçoit une application ASGI parente comme argument dans son constructeur et implémente une méthode async __call__ qui appelle cette application parente.

Certaines implémentations, telles que asgi-cors, utilisent un style alternatif qui utilise des fonctions:

Importer des functools

def asgi_middleware():
    def asgi_deciator (app):

        @functools.wraps(app)
        async def wrapped_app(scope, receive, send):
            Await App(scope, receive, send)

        return wrapped_app

    return asgi_decoreur

Quoi qu 'il en soit, le middleware ASGI doit être un objet appelable qui accepte trois paramètres:scope,receive et send.

  • scope est un dictionnaire qui contient des informations sur les connexions, où scope["type"] peut être
    • "http" : Utilisé pour les requêtes HTTP.
    • "websocket" : pour les connexions WebSocket.
    • "lifespan" : Utilisé pour les messages ASGI Lifecycle.
  • receive et send peuvent être utilisés pour échanger des messages d'événement ASGI avec un serveur ASGI-plus d'informations à ce sujet ci-dessous. le type et le contenu de ces messages dépendent du type de portée. en savoir plus dans la spécification ASGI.

Utilisation d'un middleware ASGI pur

Le middleware ASGI pur peut être utilisé comme tout autre middleware:

de starlette.applications import Starlette
de starlette.middleware import Middleware

de.middleware import ASGIMiddleware

Routes = ...

middleware = [
    Middleware(ASGIMiddleware),
]

app = Starlette(…, middleware=middleware)

Voir aussi Utilisation du middleware.

Type de commentaire

Il existe deux façons d'ajouter des annotations à un middleware: en utilisant Starlette elle-même ou asgiref.

  • Utilisation de Starlette: pour la plupart des cas d'utilisation courants.

    de starlette.types import ASGIApp, Message, Scope, Receive, Send

    Classe ASGIMiddleware: def init(self, app: ASGIApp) -> None: self.app = application

    async def __call__(self, scope: Scope, receive: Receive, send: Send) -> None:
        Si scope["type"] != "http":
            retour await self.app (scope, receive, send)
    
        async def send_wrapper(message: Message) -> None:
            #Faites quelque chose
            await send(message)
    
        await self.app (scope, receive, send_wrapper)
    
  • utilise asgiref: pour obtenir des types plus stricts.

    de asgiref.typing import ASGI3Application, ASGIReceiveCallable, ASGISendCallable, Scope asgiref.typing import ASGIReceiveEvent, ASGISendEvent

    Classe ASGIMiddleware: def init(self, app: ASGI3Application) -> None: self.app = application

    async def __call__(self, scope: Scope, receive: ASGIReceiveCallable, send: ASGISendCallable) -> None:
        Si scope["type"] != "http":
            await self.app (scope, receive, send)
            Retour à
    
        async def send_wrapper(message: ASGISendEvent) -> None:
            #Faites quelque chose
            await send(message)
    
        return await self.app (scope, receive, send_wrapper)
    

Modèles communs

Traitement de certaines demandes uniquement

Le middleware ASGI peut appliquer des comportements spécifiques en fonction du contenu de scope.

Par exemple, si seules les requêtes HTTP sont traitées, écrivez «…»

Classe ASGIMidleware:
    def __init__(self, app):
        self.app = application

    async def __call__(soi, scope, receive, send):
        Si scope["type"] != "http":
            await self.app (scope, receive, send)
            Retour à

        #Faites-en quelque chose!

        await self.app (scope, receive, send)

De même, seul le middleware de WebSocket est protégé sur scope["type"] != "websocket".

Le middleware peut également se comporter différemment en fonction de la méthode de demande, de l'URL, du premier critère.

Multiplexage de composants Starlette

Starlette fournit plusieurs structures de données qui acceptent les paramètres ASGI scope,receive et/ou send, ce qui vous permet de travailler à un niveau d'abstraction plus élevé. ces structures de données incluent Request,Headers,QueryParams,URL, etc.

Par exemple, vous pouvez instancier un Request pour vérifier plus facilement les requêtes HTTP:

de starlette.requests Demande d'importation

Classe ASGIMidleware:
    def __init__(self, app):
        self.app = application

    async def __call__(self, scope, receive, send):
        Si scope["type"] == "http":
            demande = demande (scope)
            ... # Use `request.method`,`request.url`,`request.headers`, etc.

        await self.app (scope, receive, send)

Vous pouvez également réutiliser les réponses, qui sont également des applications ASGI.

Envoyer une réponse fervente

La vérification de la connexion scope vous permet d'appeler conditionnellement à différentes applications ASGI. un cas d'utilisation pourrait être d'envoyer une réponse sans appeler l'application.

Par exemple, ce middleware utilise un dictionnaire pour effectuer une redirection permanente en fonction du chemin demandé. si vous devez reconstruire le schéma d'URL de routage, cela peut être utilisé pour implémenter un support continu pour les URL héritées.

de starlette.datastructures import URL
de starlette.responses à import RedirectResponse

Classe RedirectsMiddleware:
    def __init__(self, app, path_mapping: dict):
        self.app = application
        self.path_mapping = path_mapping

    async def __call__(self, scope, receive, send):
        Si scope["type"] != "http":
            await self.app (scope, receive, send)
            Retour sur

        url = URL(scope=scope)

        if url.path in self.path_mapping:
            url = url.replace(path=self.path_mapping[url.path])
            response = RedirectResponse(URL, status_code=301)
            Await Response(scope, receive, send)
            Retour sur

        await self.app (scope, receive, send)

Un exemple d'utilisation ressemblerait à ceci:

de starlette.applications import Starlette
de starlette.middleware import Middleware

Routes = ...

Redirections = {
    "/v1/ressource/": "/v2/ressource/",
    # ...
}

middleware = [
    Middleware(RedirectsMiddleware, path_mapping=redirections),
]

app = Starlette(routes=routes, middleware=middleware)

Demande de vérification ou de modification

Les informations de demande peuvent être consultées ou modifiées en manipulant scope. pour un exemple complet de ce mode, consultez ProxyHeadersMiddleware d'Uvicorn, qui vérifie et ajuste scope lorsqu 'il fournit des services derrière un proxy frontal.

En outre, l'enveloppement d'un objet appelable ASGI receive vous permet d'accéder ou de modifier le corps d'une requête HTTP en manipulant un message d'événement ASGI http.request.

Par exemple, ce middleware calcule et enregistre la taille du corps de la requête entrante…»

Classe LoggedRequestBodySizeMiddleware:
    def __init__(self, app):
        self.app = application

    async def __call__(soi, scope, receive, send):
        Si scope["type"] != "http":
            await self.app (scope, receive, send)
            Retour sur

        body_size = 0

        async def receive_logging_request_body_size():
            nonlocal body_size

            message = await receive()
            assert message["type"] == "http.request"

            body_size += len(message.get("body", b"))

            Si ce n'est pas message.get("more_body", False):
                print(f"Taille du corps demandé était:{body_size}octets").

            Retour message

        await self.app (scope, receive_logging_request_body_size, send)

De même, le middleware WebSocket peut manipuler le message d'événement ASGI websocket.receive pour vérifier ou modifier les données WebSocket entrantes.

Pour un exemple de modification du corps d'une requête HTTP, consultez msgpack-asgi.

Vérifier ou modifier les réponses

serait send Les objets appelables ASGI sont encapsulés et vous permettent d'examiner ou de modifier les réponses HTTP envoyées par l'application sous-jacente. http.response.start ou bien http.response.body Les messages d'événement ASGI réagissent.

Par exemple, ce middleware ajoute quelques en-têtes de réponse supplémentaires fixes:

de starlette.datastructures import MutableHeaders

Classe ExtraResponseHeadersMiddleware:
    def __init__(self, app, headers):
        self.app = application
        Self.headers = headers

    async def __call__(soi, scope, receive, send):
        Si scope["type"] != "http":
            return await self.app (scope, receive, send)

        async def send_with_extra_headers(message):
            if message["type"] == "http.response.start":
                headers = MutableHeaders(scope=message)
                pour la clé, valeur en soi-même.headers:
                    headers.append(clé, valeur)

            await send(message)

        await self.app (scope, receive, send_with_extra_headers)

Voir également asgi-logger, qui a un exemple de vérification d'une réponse HTTP et d'enregistrement d'une ligne configurable du journal d'accès HTTP.

De même, le middleware WebSocket peut manipuler les messages d'événement ASGI websocket.send pour vérifier ou modifier les données WebSocket sortantes.

Notez que si vous modifiez le corps de la réponse, vous devrez mettre à jour l'en-tête Content-Length de la réponse pour correspondre à la nouvelle longueur du corps de la réponse. voir brotli-asgi pour un exemple complet.

Transmettre des informations aux points finaux

Si vous avez besoin de partager des informations avec l'application sous-jacente ou le point de terminaison, vous pouvez les stocker dans le dictionnaire scope. Notez qu 'il s'agit d'une convention-par exemple, Starlette utilise cette méthode pour partager des informations de routage avec le point de terminaison-mais cela ne fait pas partie de la spécification ASGI. Si vous le faites, assurez-vous d'utiliser des clés qui ne sont pas susceptibles d'être utilisées par d'autres middlewares ou applications pour éviter les conflits.

Par exemple, lorsque le middleware suivant est inclus, les points de terminaison seront en mesure d'accéder à request.scope["asgi_transaction_id"].

Import uuid

Classe TransactionIDMiddleware:
    def__init__(self, app):
        self.app

    async def__call__(self, scope, receive, send):
        scope ["asgi_transaction_id"]= uuid.uuid4 ()
        await www.example.com (scope, receive, send)

Nettoyage et gestion des erreurs

Vous pouvez envelopper votre application dans un bloc try/except/finally ou dans un gestionnaire de contexte pour effectuer des opérations de nettoyage ou de gestion des erreurs.

Par exemple, le middleware suivant peut collecter des métriques et gérer les exceptions d'application...

Importer le temps

Classe MonitoringMiddleware:
    def__init__(self, app):
        self.app

    async def__call__(soi, scope, receive, send):
        start = temps. temps ()
        Essayez:
            await www.example.com (scope, receive, send)
        Exception comme exc:
            #Procéder à l'exception
            raise
        Finalement:
            Fin = temps. temps ()
            elapsed = fin-début
            ... # Submit `elapsed` comme métrique pour un backend de surveillance

Voir aussi timing-asgi pour un exemple complet de ce mode.

Problèmes potentiels

Le middleware ASGI devrait être apatride

Parce que ASGI est destiné à traiter les demandes concurrentes, tout état spécifique à la connexion devrait être limité à l'intérieur de l'implémentation __call__. ne pas le faire entraîne généralement des conflits de lecture/écriture variables entre les demandes, et des erreurs sont susceptibles de survenir.

Par exemple, si un en-tête X-Mock est présent dans la réponse, cette action remplacera conditionnellement le corps de la réponse.

  • Faites le

    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)
    
  • Ne pas

    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)
    

Voir aussi GZipMiddleware pour un exemple complet d'implémentation qui résout ce problème potentiel.

Read more about Lire plus

Cette documentation devrait être suffisante pour servir de base solide sur la façon de créer un middleware ASGI.

Cependant, il existe de nombreux excellents articles sur le sujet:

Utilisation du middleware dans d'autres frameworks

Pour envelopper un middleware ASGI autour d'autres applications ASGI, vous devez envelopper les instances d'application en utilisant un modèle plus générique:

app = TrustedHostMiddleware(app, allowed_hosts=['example.com'])

Vous pouvez également le faire avec une instance de l'application Starlette, mais il est préférable d'utiliser le style middleware=<List of Middleware instances>, car il:

  • s'assure que tout est enveloppé dans une couche externe de ServerErrorMiddleware.
  • réserve les instances app de premier niveau.

Appliquer un middleware à un groupe de routage

Le middleware peut également être ajouté à une instance Mount, ce qui vous permet d'appliquer le middleware à un ensemble de routes ou de sous-applications:

de starlette.applications import Starlette
de starlette.middleware import Middleware
from starlette.middleware.gzip import GZipMiddleware
depuis starlette.routing import Mount, Route


Routes = [
    Le mont (
        "/",
        Routes=[
            La Route(
                "/exemple",
                endpoint=…,
            )
        ],
        Middleware=[Middleware(GZipMiddleware)]
    )
]

app = Starlette(routes=routes)

Notez que le middleware utilisé de cette façon n'est pas enveloppé dans un middleware de gestion des exceptions comme celui appliqué à une application Starlette. cela ne pose généralement pas de problème car il ne s'applique qu'à la vérification ou à la modification du middleware de Response, et même dans ce cas, vous ne voudrez probablement pas appliquer cette logique aux réponses d'erreur.

  • Ajouter une ExceptionMiddleware sur Mount
  • ajoute un bloc try/except à votre middleware et renvoie une réponse d'erreur à partir de là.
  • divise le marquage et le traitement en deux middlewares, l'un placé sur Mount qui marque la réponse comme nécessitant un traitement (par exemple en configurant scope["log-response"] = True) et l'autre appliqué à l'application Starlette pour faire le gros du travail.

La classe Route/WebSocket accepte également un paramètre middleware qui vous permet d'appliquer le middleware à une seule route:

de starlette.applications import Starlette
de starlette.middleware import Middleware
from starlette.middleware.gzip import GZipMiddleware
de starlette.routing Route d'importation


Routes = [
    La Route(
        "/exemple",
        endpoint=…,
        Middleware=[Middleware(GZipMiddleware)]
    )
]

app = Starlette(routes=routes)

Vous pouvez également appliquer le middleware à la classe Router, ce qui vous permet d'appliquer le middleware à un ensemble de routes:

de starlette.applications import Starlette
de starlette.middleware import Middleware
de starlette.middleware.gzip import GZipMiddleware
de starlette.routing import Route, Router


Routes = [
    Route("/example", endpoint=...),
    Route("/another", endpoint=...),
]

Router = Router(routes=routes, middleware=[Middleware(GZipMiddleware)])

Middleware par des tiers

asgi-auth-github)

Ce middleware ajoute une authentification à toute application ASGI, obligeant les utilisateurs à se connecter à l'aide de leur compte GitHub (via OAuth). L'accès peut être limité à un utilisateur spécifique ou aux membres d'une organisation ou d'une équipe GitHub spécifique.

asgi-csrf

Middleware utilisé pour se protéger contre les attaques CSRF. Ce middleware implémente un mode de Cookie à double soumission, dans lequel un Cookie est défini, puis placé avec csrftoken pour masquer les champs de formulaire ou x-csrftoken Les en-têtes HTTP sont comparés.

Le middleware Authlib

Une alternative directe au middleware conversationnel Starlette, en utilisant le module jwt d'authlib.

Le middleware de Bugsnag

Une classe middleware pour enregistrer les exceptions dans Bugsnag.

Le middleware CSRF

Middleware utilisé pour se protéger contre les attaques CSRF. Ce middleware implémente un mode de Cookie à double soumission, dans lequel un Cookie est défini, puis comparé à un en-tête HTTP x-csrftoken.

Le middleware des premières données

Middleware et décorateur pour détecter et rejeter les demandes de données antérieures TLSv1.3.

Le middleware de Prometheus

Une classe de middleware pour capturer les métriques Prometheus liées aux demandes et aux réponses, y compris les demandes en cours, le temps, etc.

Proxy Header Middleware (en anglais)

Uvicorn contient une classe middleware pour déterminer l'adresse IP du client en fonction des en-têtes X-Forwarded-Proto et X-Forwarded-For lorsque vous utilisez un serveur proxy.

Intergiciel de limitation de débit

Une sorte de middleware limitant le taux. expressions régulières correspondant aux URL; règles flexibles; hautement personnalisable. très facile à utiliser.

RequestId middleware

Une classe middleware utilisée pour lire/générer un ID de requête et l'attacher au journal de l'application.

Le middleware Rollbar

Une classe middleware pour enregistrer les exceptions, les erreurs et les messages de journal dans Rollbar.

StarletteOpentracing

Une classe de middleware qui envoie des informations de suivi aux trackers compatibles avec OpenTracing.io et peut être utilisée pour analyser et surveiller des applications distribuées.

Un middleware personnalisable pour ajouter un cryptage et un déchiffrement automatiques des cookies à l'application Starlette, offrant un support supplémentaire aux middlewares existants basés sur les cookies.

Timing middleware pour

Une classe middleware qui émet des informations de chronométrage (temps CPU et temps horloge murale) pour chaque requête qui la traverse. inclut un exemple de la façon dont ces chronométrages sont émis en tant que métriques statsd.

par WSGIMiddleware

Une classe de middleware responsable de la conversion des applications WSGI en applications ASGI.