Middleware¶
Middleware är ett ramverk av krokar i Djangos request/response-behandling. Det är ett lätt ”plugin”-system på låg nivå för att globalt ändra Djangos in- eller utdata.
Varje middleware-komponent är ansvarig för att utföra en specifik funktion. Till exempel innehåller Django en middleware-komponent, AuthenticationMiddleware
, som associerar användare med förfrågningar med hjälp av sessioner.
Detta dokument förklarar hur middleware fungerar, hur du aktiverar middleware och hur du skriver din egen middleware. Django levereras med några inbyggda middleware som du kan använda direkt ur lådan. De är dokumenterade i inbyggd middleware-referens.
Skriva din egen middleware¶
En middleware-fabrik är en callable som tar en get_response
callable och returnerar en middleware. En middleware är en anropsbar som tar emot en begäran och returnerar ett svar, precis som en vy.
En middleware kan skrivas som en funktion som ser ut så här:
def simple_middleware(get_response):
# One-time configuration and initialization.
def middleware(request):
# Code to be executed for each request before
# the view (and later middleware) are called.
response = get_response(request)
# Code to be executed for each request/response after
# the view is called.
return response
return middleware
Eller så kan det skrivas som en klass vars instanser är anropsbara, så här:
class SimpleMiddleware:
def __init__(self, get_response):
self.get_response = get_response
# One-time configuration and initialization.
def __call__(self, request):
# Code to be executed for each request before
# the view (and later middleware) are called.
response = self.get_response(request)
# Code to be executed for each request/response after
# the view is called.
return response
Den get_response
callable som tillhandahålls av Django kan vara den faktiska vyn (om detta är den sista listade middleware) eller det kan vara nästa middleware i kedjan. Den aktuella mellanvaran behöver inte veta eller bry sig om exakt vad den är, bara att den representerar vad som kommer härnäst.
Ovanstående är en liten förenkling - den anropbara get_response
för den sista middlewaren i kedjan kommer inte att vara den faktiska vyn utan snarare en omslagsmetod från hanteraren som tar hand om att tillämpa view middleware, anropa vyn med lämpliga URL-argument och tillämpa template-response och exception middleware.
Middleware kan antingen stödja endast synkrona Python (standard), endast asynkrona Python, eller båda. Se Asynkront stöd för detaljer om hur man annonserar vad man stödjer, och vet vilken typ av förfrågan man får.
Middleware kan finnas var som helst på din Python-väg.
__init__(get_response)
¶
Middleware-fabriker måste acceptera ett get_response
-argument. Du kan också initiera ett globalt tillstånd för mellanvaran. Tänk på ett par försiktighetsåtgärder:
Django initierar din middleware med endast
get_response
argumentet, så du kan inte definiera__init__()
som kräver några andra argument.Till skillnad från metoden
__call__()
som anropas en gång per förfrågan, anropas__init__()
bara en gång, när webbservern startar.
Markera middleware som oanvänd¶
Det är ibland användbart att vid uppstart avgöra om en del av middleware ska användas. I dessa fall kan din middlewares __init__()
metod ge upphov till MiddlewareNotUsed
. Django kommer då att ta bort den middleware från middleware-processen och logga ett debug-meddelande till loggern django.begäran när DEBUG
är True
.
Aktivering av middleware¶
För att aktivera en middleware-komponent lägger du till den i listan MIDDLEWARE
i dina Django-inställningar.
I MIDDLEWARE
representeras varje middleware-komponent av en sträng: den fullständiga Python-sökvägen till middleware-fabrikens klass- eller funktionsnamn. Här är till exempel standardvärdet som skapades av django-admin startproject
:
MIDDLEWARE = [
"django.middleware.security.SecurityMiddleware",
"django.contrib.sessions.middleware.SessionMiddleware",
"django.middleware.common.CommonMiddleware",
"django.middleware.csrf.CsrfViewMiddleware",
"django.contrib.auth.middleware.AuthenticationMiddleware",
"django.contrib.messages.middleware.MessageMiddleware",
"django.middleware.clickjacking.XFrameOptionsMiddleware",
]
En Django-installation kräver inte någon middleware - MIDDLEWARE
kan vara tom om du vill - men det rekommenderas starkt att du åtminstone använder CommonMiddleware
.
Ordningen i MIDDLEWARE
är viktig eftersom ett mellanprogram kan vara beroende av andra mellanprogram. Till exempel lagrar AuthenticationMiddleware
den autentiserade användaren i sessionen; därför måste den köras efter SessionMiddleware
. Se Beställning av mellanprogramvara för några vanliga tips om ordning av Django middleware-klasser.
Ordning och skiktning av mellanprogram¶
Under förfrågningsfasen, innan vyn anropas, tillämpar Django middleware i den ordning som definieras i MIDDLEWARE
, uppifrån och ner.
Du kan tänka på det som en lök: varje middleware-klass är ett ”lager” som omsluter vyn, som finns i lökens kärna. Om begäran passerar genom alla lager i löken (varje lager anropar get_response
för att skicka begäran till nästa lager), hela vägen till vyn i kärnan, kommer svaret sedan att passera genom varje lager (i omvänd ordning) på väg tillbaka ut.
Om ett av lagren bestämmer sig för att kortsluta och returnera ett svar utan att någonsin anropa sitt get_response
, kommer inget av lagren i löken inuti det lagret (inklusive vyn) att se begäran eller svaret. Svaret kommer bara att returneras genom samma lager som begäran passerade in genom.
Andra middleware-krokar¶
Förutom det grundläggande request/response-mönstret för middleware som beskrivits tidigare kan du lägga till tre andra specialmetoder till klassbaserade middleware:
process_view()`
¶
- process_view(request, view_func, view_args, view_kwargs)¶
request
är ett HttpRequest
objekt. view_func
är den Python-funktion som Django ska använda. (Det är det faktiska funktionsobjektet, inte namnet på funktionen som en sträng.) view_args
är en lista över positionella argument som kommer att skickas till vyn, och view_kwargs
är en ordbok över nyckelordsargument som kommer att skickas till vyn. Varken view_args
eller view_kwargs
inkluderar det första vyargumentet (request
).
process_view()
anropas precis innan Django anropar vyn.
Det bör returnera antingen None
eller ett HttpResponse
-objekt. Om det returnerar None
kommer Django att fortsätta bearbeta denna begäran, köra alla andra process_view()
middleware och sedan den lämpliga vyn. Om det returnerar ett HttpResponse
-objekt kommer Django inte att bry sig om att anropa lämplig vy; det kommer att tillämpa svarsmellanprogram till det HttpResponse
och returnera resultatet.
Observera
Åtkomst till request.POST
inuti middleware innan vyn körs eller i process_view()
kommer att förhindra att en vy som körs efter middleware kan modifiera uppladdningshanterarna för begäran, och bör normalt undvikas.
Klassen CsrfViewMiddleware
kan betraktas som ett undantag, eftersom den tillhandahåller dekoratorerna csrf_exempt()
och csrf_protect()
som gör det möjligt för vyer att uttryckligen styra vid vilken tidpunkt CSRF-valideringen ska ske.
process_exception()
¶
- process_exception(request, exception)¶
request
är ett HttpRequest
objekt. exception
är ett Exception
objekt som tas upp av view funktionen.
Django anropar process_exception()
när en vy ger upphov till ett undantag. process_exception()
bör returnera antingen None
eller ett HttpResponse
-objekt. Om den returnerar ett HttpResponse
-objekt kommer mallsvaret och svarsmellanvaran att tillämpas och det resulterande svaret returneras till webbläsaren. Annars börjar :ref:standardhantering av undantag <error-views>
gälla.
Återigen körs middleware i omvänd ordning under svarsfasen, som inkluderar process_exception
. Om en undantagsmellanvara returnerar ett svar, kommer process_exception
-metoderna i mellanvaruklasserna ovanför den mellanvaran inte att anropas alls.
process_template_response()
¶
- process_template_response(request, response)¶
request
är ett HttpRequest
-objekt. response
är TemplateResponse
-objektet (eller motsvarande) som returneras av en Django-vy eller av en middleware.
process_template_response()
anropas strax efter att vyn har körts färdigt, om svarsinstansen har en render()
-metod, vilket indikerar att det är en TemplateResponse
eller motsvarande.
Den måste returnera ett svarsobjekt som implementerar en render
-metod. Det kan ändra det givna respons
genom att ändra response.template_name
och response.context_data
, eller så kan det skapa och returnera en helt ny TemplateResponse
eller motsvarande.
Du behöver inte uttryckligen rendera svaren - svaren renderas automatiskt när alla middleware för mallsvar har anropats.
Middleware körs i omvänd ordning under svarsfasen, som inkluderar process_template_response()
.
Hantering av strömmande svar¶
Till skillnad från HttpResponse
har StreamingHttpResponse
inte attributet content
. Som ett resultat kan middleware inte längre anta att alla svar kommer att ha ett content
-attribut. Om de behöver tillgång till innehållet måste de testa för strömmande svar och justera sitt beteende i enlighet därmed:
if response.streaming:
response.streaming_content = wrap_streaming_content(response.streaming_content)
else:
response.content = alter_content(response.content)
Observera
streaming_content
bör antas vara för stort för att kunna hållas i minnet. Response middleware kan omsluta det i en ny generator, men får inte konsumera det. Omslag implementeras typiskt på följande sätt:
def wrap_streaming_content(content):
for chunk in content:
yield alter_content(chunk)
StreamingHttpResponse
tillåter både synkrona och asynkrona iteratorer. Inkapslingsfunktionen måste matcha. Kontrollera StreamingHttpResponse.is_async
om din mellanvara behöver stödja båda typerna av iteratorer.
Hantering av undantag¶
Django konverterar automatiskt undantag som tas upp av vyn eller av middleware till ett lämpligt HTTP-svar med en felstatuskod. :ref:``Vissa undantag <error-views>` konverteras till 4xx-statuskoder, medan ett okänt undantag konverteras till en 500-statuskod.
Denna konvertering sker före och efter varje middleware (du kan tänka på det som den tunna filmen mellan varje lager av löken), så att varje middleware alltid kan lita på att få någon form av HTTP-svar tillbaka från anropet till dess get_response
callable. Middleware behöver inte oroa sig för att linda in sitt anrop till get_response
i en try/except
och hantera ett undantag som kan ha uppstått av en senare middleware eller vyn. Även om nästa middleware i kedjan till exempel ger upphov till ett Http404
-undantag, kommer din middleware inte att se det undantaget; istället får den ett HttpResponse
-objekt med en status_code
på 404.
Du kan sätta DEBUG_PROPAGATE_EXCEPTIONS
till True
för att hoppa över denna konvertering och sprida undantag uppåt.
Asynkront stöd¶
Middleware kan stödja alla kombinationer av synkrona och asynkrona förfrågningar. Django kommer att anpassa förfrågningar för att passa mellanvarans krav om det inte kan stödja båda, men med en prestandaförlust.
Som standard antar Django att din middleware endast kan hantera synkrona förfrågningar. För att ändra dessa antaganden, ställ in följande attribut på din middleware fabriksfunktion eller klass:
sync_capable
är en boolean som anger om mellanvaran kan hantera synkrona förfrågningar. Standardvärdet ärTrue
.async_capable
är en boolean som anger om mellanvaran kan hantera asynkrona förfrågningar. Standardvärdet ärFalse
.
Om din middleware har både sync_capable = True
och async_capable = True
, kommer Django att skicka begäran utan att konvertera den. I det här fallet kan du räkna ut om din mellanvara kommer att ta emot asynkrona förfrågningar genom att kontrollera om get_response
-objektet du skickas är en coroutine-funktion, med hjälp av asgiref.sync.iscoroutinefunction
.
Modulen django.utils.decorators
innehåller sync_only_middleware()
, async_only_middleware()
, och sync_and_async_middleware()
decorators som låter dig tillämpa dessa flaggor på middleware-fabriksfunktioner.
Den returnerade callable måste matcha sync- eller async-karaktären hos get_response
-metoden. Om du har en asynkron get_response
måste du returnera en coroutine-funktion (async def
).
metoderna process_view
, process_template_response
och process_exception
, om de tillhandahålls, bör också anpassas för att matcha sync/async-läget. Django kommer dock att anpassa dem individuellt efter behov om du inte gör det, med en extra prestandaförlust.
Här är ett exempel på hur man skapar en middleware-funktion som stöder båda:
from asgiref.sync import iscoroutinefunction
from django.utils.decorators import sync_and_async_middleware
@sync_and_async_middleware
def simple_middleware(get_response):
# One-time configuration and initialization goes here.
if iscoroutinefunction(get_response):
async def middleware(request):
# Do something here!
response = await get_response(request)
return response
else:
def middleware(request):
# Do something here!
response = get_response(request)
return response
return middleware
Observera
Om du deklarerar en hybrid middleware som stöder både synkrona och asynkrona anrop, kanske den typ av anrop du får inte matchar den underliggande vyn. Django kommer att optimera anropsstacken för mellanvaran för att ha så få sync/async-övergångar som möjligt.
Även om du wrappar en asynkron vy kan du alltså bli anropad i synkront läge om det finns annan, synkron middleware mellan dig och vyn.
När du använder en asynkron klassbaserad middleware måste du se till att instanser är korrekt markerade som coroutine-funktioner:
from asgiref.sync import iscoroutinefunction, markcoroutinefunction
class AsyncMiddleware:
async_capable = True
sync_capable = False
def __init__(self, get_response):
self.get_response = get_response
if iscoroutinefunction(self.get_response):
markcoroutinefunction(self)
async def __call__(self, request):
response = await self.get_response(request)
# Some logic ...
return response
Uppgradering av middleware i stil med före Django 1.10¶
- class django.utils.deprecation.MiddlewareMixin¶
Django tillhandahåller django.utils.deprecation.MiddlewareMixin
för att underlätta skapandet av middleware-klasser som är kompatibla med både MIDDLEWARE
och den gamla MIDDLEWARE_CLASSES
, och som stöder synkrona och asynkrona förfrågningar. Alla middleware-klasser som ingår i Django är kompatibla med båda inställningarna.
Mixinen tillhandahåller en __init__()
-metod som kräver ett get_response
-argument och lagrar det i self.get_response
.
Metoden __call__()
:
Anropar
self.process_request(request)
(om definierat).Anropar
self.get_response(request)
för att hämta svaret från senare middleware och vyn.Anropar
self.process_response(request, response)
(om definierat).Returnerar svaret.
Om den används med MIDDLEWARE_CLASSES
kommer metoden __call__()
aldrig att användas; Django anropar process_request()
och process_response()
direkt.
I de flesta fall räcker det med att ärva från denna mixin för att göra en gammal middleware kompatibel med det nya systemet med tillräcklig bakåtkompatibilitet. Den nya semantiken för kortslutning kommer att vara harmlös eller till och med fördelaktig för den befintliga mellanprogramvaran. I några få fall kan en middleware-klass behöva ändras för att anpassas till den nya semantiken.
Detta är de beteendemässiga skillnaderna mellan att använda MIDDLEWARE
och MIDDLEWARE_CLASSES
:
Under
MIDDLEWARE_CLASSES
kommer varje middleware alltid att få sin metodprocess_response
anropad, även om en tidigare middleware kortslöt genom att returnera ett svar från sin metodprocess_request
. UnderMIDDLEWARE
beter sig middleware mer som en lök: de lager som ett svar går igenom på vägen ut är samma lager som såg begäran på vägen in. Om en mellanvara kortsluts är det bara den mellanvaran och de före den iMIDDLEWARE
som kommer att se svaret.Under
MIDDLEWARE_CLASSES
tillämpasprocess_exception
på undantag som uppstår från enprocess_request
-metod för mellanprogramvara. UnderMIDDLEWARE
gällerprocess_exception
endast för undantag som uppstår från vyn (eller frånrender
-metoden i enTemplateResponse
). Undantag som tas upp från en mellanvara konverteras till lämpligt HTTP-svar och skickas sedan vidare till nästa mellanvara.Under
MIDDLEWARE_CLASSES
, om enprocess_response
-metod ger upphov till ett undantag, hoppasprocess_response
-metoderna för alla tidigare mellanprogram över och ett500 Internal Server Error
HTTP-svar returneras alltid (även om undantaget som gav upphov till t.ex. var enHttp404
). UnderMIDDLEWARE
, kommer ett undantag som uppstår från en middleware omedelbart att konverteras till lämpligt HTTP-svar, och sedan kommer nästa middleware i raden att se det svaret. Mellanprogram hoppas aldrig över på grund av att ett mellanprogram ger upphov till ett undantag.