Maison > développement back-end > Tutoriel Python > Qu'est-ce qu'un middleware ? Analyse du middleware Django en python

Qu'est-ce qu'un middleware ? Analyse du middleware Django en python

不言
Libérer: 2018-09-25 17:02:48
original
3209 Les gens l'ont consulté

Le contenu de cet article porte sur ce qu'est un middleware ? L'analyse du middleware Django en python a une certaine valeur de référence. Les amis dans le besoin peuvent s'y référer, j'espère qu'elle vous sera utile.

Qu'est-ce que le middleware ?

Déclaration officielle : le middleware est un hook au niveau du framework utilisé pour gérer les requêtes et les réponses de Django. Il s'agit d'un système de plug-in léger de bas niveau permettant de modifier globalement les entrées et sorties de Django. Chaque composant middleware est chargé d’exécuter certaines fonctions spécifiques.

Mais parce que cela affecte la situation mondiale, il doit être utilisé avec prudence. Une mauvaise utilisation affectera les performances.

Pour parler franchement, le middleware nous aide à effectuer quelques opérations supplémentaires avant et après l'exécution de la fonction d'affichage. Il s'agit essentiellement d'une classe personnalisée avec plusieurs méthodes définies dans la classe. Le framework exécutera ces méthodes au niveau. heure spécifiée demandée.

Nous avons utilisé un middleware, mais nous ne l'avons tout simplement pas remarqué. Ouvrez le fichier Settings.py du projet Django et voyez l'élément de configuration MIDDLEWARE dans l'image ci-dessous.

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',
]
Copier après la connexion

L'élément de configuration MIDDLEWARE est une liste, et la liste est une chaîne. Ces chaînes sont en fait des classes, c'est-à-dire des middleware.

Jetons ensuite un coup d'œil aux méthodes du middleware et au moment où ces méthodes sont exécutées.

Middleware personnalisé

Le middleware peut définir cinq méthodes, à savoir : (les principales sont process_request et 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, réponse)

Ci-dessus La valeur de retour de la méthode peut être None ou un objet HttpResponse. Si c'est None, elle continuera à s'exécuter à rebours selon les règles définies par Django. S'il s'agit d'un objet HttpResponse, l'objet sera renvoyé directement à l'utilisateur.

Personnaliser un exemple de middleware

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
Copier après la connexion

process_request

process_request a un paramètre, qui est request. Cette requête est la même que la requête dans la fonction d'affichage.

Sa valeur de retour peut être None ou un objet HttpResponse. Si la valeur de retour est None, continuez selon le processus normal et remettez-la au prochain middleware pour traitement. S'il s'agit d'un objet HttpResponse, Django n'exécutera pas la fonction d'affichage et ne renverra pas l'objet correspondant au navigateur.

Voyons comment Django exécute la méthode process_request lorsqu'il existe plusieurs middlewares

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
Copier après la connexion

Enregistrez les deux middlewares personnalisés ci-dessus dans l'élément de configuration MIDDLEWARE du fichier 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
]
Copier après la connexion

A ce moment, lorsque nous accédons à une vue, nous trouverons le contenu suivant imprimé dans le terminal :

第一个里面的 process_request
第二个里面的 process_request
app01 中的 index视图
Copier après la connexion

Remplacez les positions de MD1 et MD2, puis accédez à une vue , Vous constaterez que le contenu imprimé dans le terminal est le suivant :

第二个里面的 process_request
第一个里面的 process_request
app01 中的 index视图
Copier après la connexion

En regardant les résultats, nous savons que la fonction view est exécutée en dernier, et la seconde exécute sa propre méthode process_request avant le le premier.

Lorsque vous imprimez les paramètres de requête dans la méthode process_request dans les deux middlewares personnalisés, vous constaterez qu'il s'agit du même objet.

Pour résumer :

  1. La méthode process_request du middleware est exécutée avant l'exécution de la fonction d'affichage.

  2. Lors de la configuration de plusieurs middlewares, ils seront exécutés dans l'ordre d'avant en arrière selon l'ordre d'enregistrement dans MIDDLEWARE, c'est-à-dire la valeur d'index de la liste.

  3. Les requêtes transmises entre différents middlewares sont toutes le même objet

La méthode process_response dans plusieurs middlewares est selon MIDDLEWARE L'ordre d'enregistrement est exécuté dans l'ordre inverse , c'est-à-dire que la méthode process_request du premier middleware est exécutée en premier, et sa méthode process_response est exécutée en dernier. La méthode process_request du dernier middleware est exécutée en dernier, et sa méthode process_response est exécutée en dernier. Exécuté en premier.

process_response

Il a deux paramètres, l'un est une requête et l'autre est une réponse. Request est le même objet que dans l'exemple ci-dessus, et la réponse est l'objet HttpResponse renvoyé par la fonction d'affichage. La valeur de retour de cette méthode doit également être un objet HttpResponse.

Ajoutez la méthode process_response aux M1 et M2 ci-dessus :

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
Copier après la connexion

Accédez à une vue et regardez la sortie du terminal :

第二个里面的 process_request
第一个里面的 process_request
app01 中的 index视图
第一个里面的 process_response
第二个里面的 process_response
Copier après la connexion

Regardez le résultat :

La méthode process_response est exécutée après la fonction view, et l'ordre est que MD1 soit exécuté avant MD2. (À l'heure actuelle, MD2 dans settings.py est enregistré avant MD1)

La méthode process_response dans plusieurs middlewares est exécutée conformément à l'ordre d'enregistrement dans MIDDLEWAREordre inverse, c'est-à-dire , la première La méthode process_request du middleware est exécutée en premier et sa méthode process_response est exécutée en dernier. La méthode process_request du dernier middleware est exécutée en dernier et sa méthode process_response est exécutée en premier.

process_view

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

Cette méthode a quatre paramètres

request est un objet HttpRequest.

view_func est la fonction d'affichage que Django utilisera bientôt. (C'est l'objet fonction réel, pas le nom de la fonction sous forme de chaîne.)

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__)
Copier après la connexion

访问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
Copier après la connexion

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")
Copier après la connexion

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

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

def index(request):    
print("app01 中的 index视图")    
raise ValueError("呵呵")    
return HttpResponse("O98K")
Copier après la connexion

在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))  # 返回一个响应对象
Copier après la connexion

看输出结果:

第二个里面的 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
Copier après la connexion

注意,这里并没有执行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
Copier après la connexion

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
Copier après la connexion

访问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
Copier après la connexion

从结果看出:

视图函数执行完之后,立即执行了中间件的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请求流程图

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Étiquettes associées:
source:php.cn
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal