Heim >Backend-Entwicklung >Python-Tutorial >Was ist Middleware? Analyse der Django-Middleware in Python

Was ist Middleware? Analyse der Django-Middleware in Python

不言
不言Original
2018-09-25 17:02:483206Durchsuche

Der Inhalt dieses Artikels befasst sich mit der Frage, was Middleware ist. Die Analyse der Django-Middleware in Python hat einen gewissen Referenzwert. Freunde in Not können sich darauf beziehen.

Was ist Middleware?

Offizielle Aussage: Middleware ist ein Hook auf Framework-Ebene, der zur Verarbeitung von Django-Anfragen und -Antworten verwendet wird. Es handelt sich um ein leichtes Low-Level-Plug-in-System zur globalen Änderung der Ein- und Ausgabe von Django. Jede Middleware-Komponente ist für die Ausführung bestimmter Funktionen verantwortlich.

Da es sich jedoch auf die Gesamtsituation auswirkt, muss es mit Vorsicht angewendet werden. Eine unsachgemäße Verwendung beeinträchtigt die Leistung.

Um es ganz klar auszudrücken: Middleware hilft uns bei der Ausführung einiger zusätzlicher Vorgänge vor und nach der Ausführung der Ansichtsfunktion. Es handelt sich im Wesentlichen um eine benutzerdefinierte Klasse mit mehreren in der Klasse definierten Methoden angegebene Zeit angefordert.

Wir haben Middleware verwendet, aber es ist uns einfach nicht aufgefallen. Öffnen Sie die Settings.py-Datei des Django-Projekts und sehen Sie sich das MIDDLEWARE-Konfigurationselement im Bild unten an.

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',
]

MIDDLEWARE-Konfigurationselement ist eine Liste, und die Liste ist eine Zeichenfolge. Diese Zeichenfolgen sind eigentlich Klassen, also Middleware.

Dann werfen wir einen Blick auf die Methoden in der Middleware und darauf, wann diese Methoden ausgeführt werden.

Benutzerdefinierte Middleware

Middleware kann fünf Methoden definieren, nämlich: (die wichtigsten sind „process_request“ und „process_response“)

  • process_request(self,request)

  • process_view(self, request, view_func, view_args, view_kwargs)

  • process_template_response(self,request,response)

  • process_Exception(self, request, Exception)

  • process_response(self, request, Response)

Oben Der Rückgabewert von Die Methode kann None oder ein HttpResponse-Objekt sein. Wenn sie None ist, wird sie gemäß den von Django definierten Regeln weiterhin ausgeführt. Wenn es sich um ein HttpResponse-Objekt handelt, wird das Objekt direkt an den Benutzer zurückgegeben.

Anpassen eines Middleware-Beispiels

from django.utils.deprecation import MiddlewareMixin
class MD1(MiddlewareMixin):
    def process_request(self, request):
        print("第一个里面的 process_request")
    def process_response(self, request, response):
        print("第二个里面的 process_response")
        return response

process_request

process_request hat einen Parameter, nämlich request. Diese Anfrage ist dieselbe wie die Anfrage in der Ansichtsfunktion.

Sein Rückgabewert kann None oder ein HttpResponse-Objekt sein. Wenn der Rückgabewert None ist, fahren Sie mit dem normalen Prozess fort und übergeben Sie ihn zur Verarbeitung an die nächste Middleware. Wenn es sich um ein HttpResponse-Objekt handelt, führt Django die Ansichtsfunktion nicht aus und gibt das entsprechende Objekt an den Browser zurück.

Sehen wir uns an, wie Django die Methode „process_request“ ausführt, wenn mehrere Middlewares vorhanden sind

from django.utils.deprecation import MiddlewareMixin
class MD1(MiddlewareMixin):
    def process_request(self, request):
        print("第一个里面的 process_request")
class MD2(MiddlewareMixin):
    def process_request(self, request):
        print("第二个里面的 process_request")
        pass

Registrieren Sie die beiden oben genannten benutzerdefinierten Middlewares im MIDDLEWARE-Konfigurationselement von Settings.py:

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',
    'middlewares.MD1',  # 自定义中间件MD1
    'middlewares.MD2'  # 自定义中间件MD2
]

Wenn wir zu diesem Zeitpunkt eine Ansicht besuchen, finden wir im Terminal den folgenden gedruckten Inhalt:

第一个里面的 process_request
第二个里面的 process_request
app01 中的 index视图

Vertauschen Sie die Positionen von MD1 und MD2 und besuchen Sie dann eine Ansicht. Wir finden Folgendes gedruckt im Terminal Der Inhalt lautet wie folgt:

第二个里面的 process_request
第一个里面的 process_request
app01 中的 index视图

Wenn wir uns die Ergebnisse ansehen, wissen wir, dass die Ansichtsfunktion zuletzt ausgeführt wird und die zweite ihre eigene Methode „process_request“ vor der ersten ausführt.

Wenn Sie die Anforderungsparameter in der Methode „process_request“ in den beiden benutzerdefinierten Middlewares drucken, werden Sie feststellen, dass es sich um dasselbe Objekt handelt.

Zusammenfassend:

  1. Die Methode „process_request“ der Middleware wird vor der Ausführung der Ansichtsfunktion ausgeführt.

  2. Bei der Konfiguration mehrerer Middlewares werden diese der Reihe nach von vorne nach hinten entsprechend der Registrierungsreihenfolge in MIDDLEWARE, also dem Indexwert der Liste, ausgeführt.

  3. Die zwischen verschiedenen Middleware weitergeleiteten Anforderungen sind alle dasselbe Objekt

Die Methode „process_response“ in mehreren Middleware entspricht der Registrierungsreihenfolge von MIDDLEWARE in umgekehrter Reihenfolge , das heißt, die Methode „process_request“ der ersten Middleware wird zuerst und ihre Methode „process_response“ zuletzt ausgeführt. Die Methode „process_request“ der letzten Middleware wird zuletzt ausgeführt Zuerst ausgeführt.

process_response

Es verfügt über zwei Parameter, einen Request und einen Response. Request ist dasselbe Objekt wie im obigen Beispiel, und Response ist das von der Ansichtsfunktion zurückgegebene HttpResponse-Objekt. Der Rückgabewert dieser Methode muss ebenfalls ein HttpResponse-Objekt sein.

Fügen Sie die Methode „process_response“ zu M1 und M2 oben hinzu:

from django.utils.deprecation import MiddlewareMixin
class MD1(MiddlewareMixin):
    def process_request(self, request):
        print("第一个里面的 process_request")
    def process_response(self, request, response):
        print("第一个里面的 process_response")
        return response
class MD2(MiddlewareMixin):
    def process_request(self, request):
        print("第二个里面的 process_request")
        pass
    def process_response(self, request, response):
        print("第二个里面的 process_response")
        return response

Öffnen Sie eine Ansicht und sehen Sie sich die Terminalausgabe an:

第二个里面的 process_request
第一个里面的 process_request
app01 中的 index视图
第一个里面的 process_response
第二个里面的 process_response

Sehen Sie sich das Ergebnis an:

process_response wird nach der Ansichtsfunktion ausgeführt, und die Reihenfolge ist, dass MD1 vor MD2 ausgeführt wird. (Zu diesem Zeitpunkt wird MD2 in Settings.py vor MD1 registriert)

Die Methode „process_response“ in mehreren Middlewares wird gemäß der Registrierungsreihenfolge in MIDDLEWARE

umgekehrte Reihenfolge ausgeführt, d. h , die erste Die Methode „process_request“ der Middleware wird zuerst ausgeführt, und ihre Methode „process_response“ wird zuletzt ausgeführt. Die Methode „process_request“ der letzten Middleware wird zuletzt ausgeführt, und ihre Methode „process_response“ wird zuerst ausgeführt.

process_view

process_view(self, request, view_func, view_args, view_kwargs)

Diese Methode hat vier Parameter

request ist ein HttpRequest-Objekt.

view_func ist die Ansichtsfunktion, die Django bald verwenden wird. (Es ist das eigentliche Funktionsobjekt, nicht der Name der Funktion als String.)

view_args是将传递给视图的位置参数的列表.

view_kwargs是将传递给视图的关键字参数的字典。 view_args和view_kwargs都不包含第一个视图参数(request)。

Django会在调用视图函数之前调用process_view方法。

它应该返回None或一个HttpResponse对象。 如果返回None,Django将继续处理这个请求,执行任何其他中间件的process_view方法,然后在执行相应的视图。 如果它返回一个HttpResponse对象,Django不会调用适当的视图函数。 它将执行中间件的process_response方法并将应用到该HttpResponse并返回结果。

 给MD1和MD2添加process_view方法:

from django.utils.deprecation import MiddlewareMixin
class MD1(MiddlewareMixin):
    def process_request(self, request):
        print("第一个里面的 process_request")
    def process_response(self, request, response):
        print("第一个里面的 process_response")
        return response
    def process_view(self, request, view_func, view_args, view_kwargs):
        print("-" * 80)
        print("第一个中的process_view")
        print(view_func, view_func.__name__)
class MD2(MiddlewareMixin):
    def process_request(self, request):
        print("第二个里面的 process_request")
        pass
    def process_response(self, request, response):
        print("第二个里面的 process_response")
        return response
    def process_view(self, request, view_func, view_args, view_kwargs):
        print("-" * 80)
        print("第二个中的process_view")
        print(view_func, view_func.__name__)

访问index视图函数,看一下输出结果:

第二个里面的 process_request
第一个里面的 process_request
--------------------------------------------------------------------------------
第二个 中的process_view
<function index at 0x000001DE68317488> index
--------------------------------------------------------------------------------
第一个 中的process_view
<function index at 0x000001DE68317488> index
app01 中的 index视图
第一个里面的 process_response
第二个里面的 process_response

process_view方法是在process_request之后,视图函数之前执行的,执行顺序按照MIDDLEWARE中的注册顺序从前到后顺序执行的

process_exception

process_exception(self, request, exception)

该方法两个参数:

一个HttpRequest对象

一个exception是视图函数异常产生的Exception对象。

这个方法只有在视图函数中出现异常了才执行,它返回的值可以是一个None也可以是一个HttpResponse对象。如果是HttpResponse对象,Django将调用模板和中间件中的process_response方法,并返回给浏览器,否则将默认处理异常。如果返回一个None,则交给下一个中间件的process_exception方法来处理异常。它的执行顺序也是按照中间件注册顺序的倒序执行。

 给MD1和MD2添加上这个方法:

from django.utils.deprecation import MiddlewareMixin
class MD1(MiddlewareMixin):
    def process_request(self, request):
        print("第一个里面的 process_request")
    def process_response(self, request, response):
        print("第一个里面的 process_response")
        return response
    def process_view(self, request, view_func, view_args, view_kwargs):
        print("-" * 80)
        print("第一个中的process_view")
        print(view_func, view_func.__name__)
    def process_exception(self, request, exception):
        print(exception)
        print("第一个中的process_exception")
class MD2(MiddlewareMixin):
    def process_request(self, request):
        print("第二个里面的 process_request")
        pass
    def process_response(self, request, response):
        print("第二个里面的 process_response")
        return response
    def process_view(self, request, view_func, view_args, view_kwargs):
        print("-" * 80)
        print("第二个中的process_view")
        print(view_func, view_func.__name__)
    def process_exception(self, request, exception):
        print(exception)
        print("第二个 中的process_exception")

如果视图函数中无异常,process_exception方法不执行。

想办法,在视图函数中抛出一个异常:

def index(request):    
print("app01 中的 index视图")    
raise ValueError("呵呵")    
return HttpResponse("O98K")

在MD1的process_exception中返回一个响应对象:

class MD1(MiddlewareMixin):
    def process_request(self, request):
        print("第一个里面的 process_request")
    def process_response(self, request, response):
        print("第一个里面的 process_response")
        return response
    def process_view(self, request, view_func, view_args, view_kwargs):
        print("-" * 80)
        print("第一个中的process_view")
        print(view_func, view_func.__name__)
    def process_exception(self, request, exception):
        print(exception)
        print("第一个中的process_exception")
        return HttpResponse(str(exception))  # 返回一个响应对象

看输出结果:

第二个里面的 process_request
第一个里面的 process_request
--------------------------------------------------------------------------------
第二个 中的process_view
<function index at 0x0000022C09727488> index
--------------------------------------------------------------------------------
第一个 中的process_view
<function index at 0x0000022C09727488> index
app01 中的 index视图
呵呵
第一个 中的process_exception
第一个里面的 process_response
第二个里面的 process_response

注意,这里并没有执行MD2的process_exception方法,因为MD1中的process_exception方法直接返回了一个响应对象。

process_template_response(用的比较少)

process_template_response(self, request, response)

它的参数,一个HttpRequest对象,response是TemplateResponse对象(由视图函数或者中间件产生)。

process_template_response是在视图函数执行完成后立即执行,但是它有一个前提条件,那就是视图函数返回的对象有一个render()方法(或者表明该对象是一个TemplateResponse对象或等价方法)。

from django.utils.deprecation import MiddlewareMixin
class MD1(MiddlewareMixin):
    def process_request(self, request):
        print("第一个里面的 process_request")
    def process_response(self, request, response):
        print("第一个里面的 process_response")
        return response
    def process_view(self, request, view_func, view_args, view_kwargs):
        print("-" * 80)
        print("第一个中的process_view")
        print(view_func, view_func.__name__)
    def process_exception(self, request, exception):
        print(exception)
        print("第一个中的process_exception")
    def process_template_response(self, request, response):
        print("第一个中的process_template_response")
        return response
class MD2(MiddlewareMixin):
    def process_request(self, request):
        print("第二个里面的 process_request")
        pass
    def process_response(self, request, response):
        print("第二个里面的 process_response")
        return response
    def process_view(self, request, view_func, view_args, view_kwargs):
        print("-" * 80)
        print("第二个中的process_view")
        print(view_func, view_func.__name__)
    def process_exception(self, request, exception):
        print(exception)
        print("第二个 中的process_exception")
    def process_template_response(self, request, response):
        print("第二个中的process_template_response")
        return response

views.py中:

def index(request):
    print("app01 中的 index视图")
    def render():
        print("in index/render")
        return HttpResponse("O98K")
    rep = HttpResponse("OK")
    rep.render = render
    return rep

访问index视图,终端输出的结果:

第二个里面的 process_request
第一个里面的 process_request
--------------------------------------------------------------------------------
第二个 中的process_view
<function index at 0x000001C111B97488> index
--------------------------------------------------------------------------------
第一个 中的process_view
<function index at 0x000001C111B97488> index
app01 中的 index视图
第一个 中的process_template_response
第二个 中的process_template_response
in index/render
第一个里面的 process_response
第二个里面的 process_response

从结果看出:

视图函数执行完之后,立即执行了中间件的process_template_response方法,顺序是倒序,先执行MD1的,在执行MD2的,接着执行了视图函数返回的HttpResponse对象的render方法,返回了一个新的HttpResponse对象,接着执行中间件的process_response方法。

中间件的执行流程

上一部分,我们了解了中间件中的5个方法,它们的参数、返回值以及什么时候执行,现在总结一下中间件的执行流程。

请求到达中间件之后,先按照正序执行每个注册中间件的process_reques方法,process_request方法返回的值是None,就依次执行,如果返回的值是HttpResponse对象,不再执行后面的process_request方法,而是执行当前对应中间件的process_response方法,将HttpResponse对象返回给浏览器。也就是说:如果MIDDLEWARE中注册了6个中间件,执行过程中,第3个中间件返回了一个HttpResponse对象,那么第4,5,6中间件的process_request和process_response方法都不执行,顺序执行3,2,1中间件的process_response方法。

process_request方法都执行完后,匹配路由,找到要执行的视图函数,先不执行视图函数,先执行中间件中的process_view方法,process_view方法返回None,继续按顺序执行,所有process_view方法执行完后执行视图函数。假如中间件3 的process_view方法返回了HttpResponse对象,则4,5,6的process_view以及视图函数都不执行,直接从最后一个中间件,也就是中间件6的process_response方法开始倒序执行。

 

process_template_response和process_exception两个方法的触发是有条件的,执行顺序也是倒序。总结所有的执行流程如下:

附:Django请求流程图

Das obige ist der detaillierte Inhalt vonWas ist Middleware? Analyse der Django-Middleware in Python. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn

In Verbindung stehende Artikel

Mehr sehen