zoukankan      html  css  js  c++  java
  • Django中间件

    Django 中间件

    我们从浏览器发出一个请求 Request,得到一个响应后的内容 HttpResponse ,这个请求传递到 Django的过程如下:

    在django项目的settings模块中,有一个 MIDDLEWARE_CLASSES 变量,其中每一个元素就是一个中间件,如下图。

    上图中是Django内部的中间件,这里我们可以看看其源码到底Django的中间件是什么东西:

    1.进入中间件的方法:

    from django.middleware.csrf import CsrfViewMiddleware   #这里我随便导入下面中间件中的其中一个点击进入该中间件的导入方法(CsrfViewMiddleware)中进一步查看
    
    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',
        'md.middleware.M1',
    ]
    

    2.查看方法的源码信息:

    class CsrfViewMiddleware(MiddlewareMixin):    #源码中该方法是一个类且继承了MiddlewareMixin的方法
        """
        Middleware that requires a present and correct csrfmiddlewaretoken
        for POST requests that have a CSRF cookie, and sets an outgoing
        CSRF cookie.
    
        This middleware should be used in conjunction with the csrf_token template
        tag.
        """
        # The _accept and _reject methods currently only exist for the sake of the
        # requires_csrf_token decorator.
        def _accept(self, request):
            # Avoid checking the request twice by adding a custom attribute to
            # request.  This will be relevant when both decorator and middleware
            # are used.
            request.csrf_processing_done = True
            return None
    

    3.进入MiddlewareMixin方法中:

    class MiddlewareMixin(object):
        def __init__(self, get_response=None):
            self.get_response = get_response
            super(MiddlewareMixin, self).__init__()
    
        def __call__(self, request):
            response = None
            if hasattr(self, 'process_request'):
                response = self.process_request(request)
            if not response:
                response = self.get_response(request)
            if hasattr(self, 'process_response'):
                response = self.process_response(request, response)
            return response
    

    从MiddlewareMixin的源码中我们可以发现其 是修改 Django request 或者 response 对象的钩子.

    在中间件中可以定义四个方法,分别是:

    1. process_request(self,request)
    2. process_view(self,request,callback,callback_args,callback_kwargs)
    3. process_template_response(self,request,response)
    4. process_exception(self, request, exception)
    5. process_response(self, request, response)
    

    以上方法的返回值可以是None和HttpResonse对象,如果是None,则继续按照django定义的规则向下执行,如果是HttpResonse对象,则直接将该对象返回给用户。

    一、process_request&process_response

    通过对MiddlewareMixin的源码和Django的内部中间件我们可以自己定义中间件:

    1.导入:

    方式1:

    在csrf.py文件中我们了解了Django的内部中间件的导入方式,所以我们也同样的继承它的方式进行导入

    from django.utils.deprecation import MiddlewareMixin
    

    方式2:

    因为考虑到方式1的导入方式已经在1.7往后版本中被废弃,所以还有下面这种导入方式,即直接将MiddlewareMixin的源码
    粘贴到你当前的py文件中:

    class MiddlewareMixin(object):
        def __init__(self, get_response=None):
            self.get_response = get_response
            super(MiddlewareMixin, self).__init__()
    
        def __call__(self, request):
            response = None
            if hasattr(self, 'process_request'):
                response = self.process_request(request)
            if not response:
                response = self.get_response(request)
            if hasattr(self, 'process_response'):
                response = self.process_response(request, response)
            return response
    

    2.定义中间件class

    from django.utils.deprecation import MiddlewareMixin
    
    class M1(MiddlewareMixin): 
        def process_request(self,request):    
            print("m1.process_request")
            
        def process_response(self,request,response):
            print('m1.process_response')
            return response
    

    这里需要注意的是上述代码我们的格式是遵循Django的格式方式进行,即在类中定义两个方法(process_request和process_response)且只有process_response有return值。这里process_respons返回值是必须需要的因为执行过程中在视图的返回的HttpResponse的返回值就就是通过process_respons一层层的进行往上return的,所以process_respons的返回值没有代码则会报错。

    3.在setting文件中将我们自定义的中间件进行导入

    MIDDLEWARE = [
        'md.middleware.M1',      #自定义中间件写的路径导入
        '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',
    
    ]
    

    4.执行过程

    下图是正常的一个执行过程,

    "D:开发工具PyCharm 5.0.3in
    unnerw.exe" "D:Program Filespython.exe" E:/py_code/DYA918/manage.py runserver 8000
    Performing system checks...
    
    System check identified no issues (0 silenced).
    September 22, 2017 - 17:32:33
    Django version 1.11.4, using settings 'DYA918.settings'
    Starting development server at http://127.0.0.1:8000/
    Quit the server with CTRL-BREAK.
    
    [22/Sep/2017 17:32:52] "GET /favicon.ico HTTP/1.1" 404 1962
    
    m1.process_request
    进入login视图
    m1.process_response
    
    
    [22/Sep/2017 17:33:02] "GET /login.html/ HTTP/1.1" 404 1962
    

    process_request方法进行用户登录验证:

    常规的中间件的process_request方法中是没有return方法的,加上return后的执行过程又会是怎样呢:

    所以依照这个特性我们就可以在自定义的中间件中定义一个用户登录验证,但是需要注意的是这个自定义的中间件需要放在Django的中间件最后,因为session的中间件在第三个,我们只能放在其之后如下代码:

    class M1(MiddlewareMixin):
        def process_request(self,request):  
            if request.path_info == '/login.html':   #这里如果url是login则直接让该请求放下去
                return None
            if not request.session.get('user_info'):  #这里如果其session中未登录则增加return让其重新登录
                return redirect('/login.html')
            
        def process_response(self,request,response):
            print('m1.process_response')
    

    二、process_view

    相同的我们也在csrf.py文件中将process_view的继承的方法继承过来:

    • 自定义的中间件:

        class M1(MiddlewareMixin):
            def process_request(self,request):
                print('m1.process_request')
            def process_response(self,request,response):
                print('m1.process_response')
            def process_view(self,view_func,view_func_args,view_func_kwargs):
                print('m1.process_view')
        class M2(MiddlewareMixin):
            def process_request(self,request):
                print('m2.process_request')
            def process_response(self,request,response):
                print('m2.process_response')
            def process_view(self,view_func,view_func_args,view_func_kwargs):
                print('m2.process_view')
      
    • setting配置:

        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',
            'md.middleware.M1',
            'md.middleware.M2',
        ]
      
    • 执行的过程

        "D:开发工具PyCharm 5.0.3in
      unnerw.exe" "D:Program Filespython.exe" E:/py_code/DYA918/manage.py runserver 8000
        Performing system checks...
        
        System check identified no issues (0 silenced).
        September 22, 2017 - 17:32:33
        Django version 1.11.4, using settings 'DYA918.settings'
        Starting development server at http://127.0.0.1:8000/
        Quit the server with CTRL-BREAK.
        [22/Sep/2017 17:32:51] "GET / HTTP/1.1" 200 1716
        
        m1.process_request
        m2.process_request
        m1.process_view
        m2.process_view
        m2.process_response
        m1.process_response
      

    通过执行的结果我们可以了解process_view在中间件中的运行过程如下图所示:

    当m2.process_view中有return值时

    • 在M1的process_view中使用return值:

        class M1(MiddlewareMixin):
            def process_request(self,request):
                print('m1.process_request')
            def process_response(self,request,response):
                print('m1.process_response')
            def process_view(self,view_func,view_func_args,view_func_kwargs):
                return HttpResponse("Whatmini")
        class M2(MiddlewareMixin):
            def process_request(self,request):
                print('m2.process_request')
            def process_response(self,request,response):
                print('m2.process_response')
            def process_view(self,view_func,view_func_args,view_func_kwargs):
                print('m2.process_view')
      
    • 执行结果

        "D:开发工具PyCharm 5.0.3in
      unnerw.exe" "D:Program Filespython.exe" E:/py_code/DYA918/manage.py runserver 8000
        Performing system checks...
        
        System check identified no issues (0 silenced).
        September 22, 2017 - 17:32:33
        Django version 1.11.4, using settings 'DYA918.settings'
        Starting development server at http://127.0.0.1:8000/
        Quit the server with CTRL-BREAK.
        [22/Sep/2017 17:32:51] "GET / HTTP/1.1" 200 1716
        
        m1.process_request
        m2.process_request
        m1.process_view
        m2.process_response
        m1.process_response
      

    这里我们可以知道当某个中间件的process_view中有return值时,其不会再往下去执行下一个中间件的process_view,同时也不会执行视图而是直接执行所有的中间件的process_response的方法,并将该return值返回给客户端

    三、porcess_exception

    • 定义中间件

        class M1(MiddlewareMixin):
            def process_request(self,request):
                print('m1.process_request')
            def process_response(self,request,response):
                print('m1.process_response')
            def process_view(self,view_func,view_func_args,view_func_kwargs):
                return HttpResponse("Whatmini")
        class M2(MiddlewareMixin):
            def process_request(self,request):
                print('m2.process_request')
            def process_response(self,request,response):
                print('m2.process_response')
            def process_view(self,view_func,view_func_args,view_func_kwargs):
                print('m2.process_view')
            def porcess_exception(self,request,exception):
                return HttpResponse("开发的程序员已经被打死")	
      

    Django的porcess_exception方法是用来捕捉项目执行过程中的报错信息的,

  • 相关阅读:
    构造函数初始化与赋值
    C代码中如何调用C++ C++中如何调用C
    C用函数指针模拟重载 C++重载
    【2019.10.30】意料之外的小黄衫——获得小黄衫感言
    【2019.10.30】SDN上机第1次作业
    【2019.10.17】十天Web前端程序员体验(软件工程实践第五次作业)
    【2019.10.07】《重生之我是程序员》
    【2019.09.30】“福大同好”——原型设计展示~
    【2019.09.30】构建之法《四五八章读后感》
    【2019.09.25】《构建之法》前三章读后感
  • 原文地址:https://www.cnblogs.com/lijian-22huxiaoshan/p/7637595.html
Copyright © 2011-2022 走看看