zoukankan      html  css  js  c++  java
  • django Middleware

    Middleware简介

    Middleware是一个轻量级的,全局性质的Django请求/响应处理钩子框架。所谓钩子框架是指在request请求到达Django之后,views视图处理之前,提前对request请求进行预处理,如禁止某些主机访问当前URL,如果request中没有携带cookie则只允许访问特定的网页等。当views处理完request请求后返回httpresponse,middleware还可以对views返回的httpresponse进行处理改变输出结果等。

    用户编写自己的Middleware时,Django为我们提供五个方法:

    • process_request(request)
    • process_response(request,response)
    • process_view(request, view_func, view_args, view_kwargs)
    • process_exception(request, exception)
    • process_template_response(request, response)

    在介绍五个方法之前,先准备下Django环境。

    工具环境:windws 7 x64  pycharm2018  python 3.6.2  django 1.11.20

    关于上述 软件安装这里不做演示。

    Django程序:

    项目:django_temp

    在django_temp/django_temp/目录下创建views.py,views.py内容如下:

    from django.shortcuts import render
    
    # Create your views here.
    def index(request):
        print('views function')
        return render(request,'index.html')

    在django_temp/templates/目录下创建index.html,index.html内容如下:

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
    <h1>Hello World</h1>
    </body>
    </html>

    在django_temp/django_temp/urls.py中添加路由。

    from django.conf.urls import url
    from django.contrib import admin
    from . import views
    urlpatterns = [
        url(r'^admin/', admin.site.urls),
        url(r'^index/', views.index),
    ]

    此时我们运行django,访问http://127.0.0.1:8000/index/应该能看到如下:

    上面的测试环境搭建好后,下面来了解django为我们写中间件时提供的五个方法。

    process_request

    process_request(request):request请求到达Django之后,views视图处理之前,提前对request请求进行一些预处理,如禁止某些主机访问当前URL。

    参数:

    request:wsgi格式的request请求。

    返回值:必须是None或者Httpresponse,如果返回None。则按照Middleware的注册顺序依次向下执行,直到运行View视图。如果返回的是Httpresponse,则在当前Middleware处返回Httpresponse。

    示例一 Middleware的加载顺序。

    在django_temp/目录下创建Middleware_test.py,该文件内容如下:

    from django.utils.deprecation import MiddlewareMixin
    from django.shortcuts import HttpResponse
    
    class Middleware01(MiddlewareMixin):
        def process_request(self,request):
            print('request  01')
    
    class Middleware02(MiddlewareMixin):
        def process_request(self,request):
            print('request  02')

    Middleware_test.py便是我们编写的Middleware,此时我们还需要在django_temp/django_temp/settings.py中激活我们的Middleware。

    在settings.py中添加如下内容:

    添加完成后,重启django,在访问http://127.0.0.1:8000/index/,我们会看到如下:

    为了验证Middleware是否是按照顺序从上至下,我们将Middleware01和Middleware02换下位置,在此查看结果

    示例二  直接返回Httpresponse

    修改Middleware_test.py中内容:

    from django.utils.deprecation import MiddlewareMixin
    from django.shortcuts import HttpResponse
    class Middleware01(MiddlewareMixin):
        def process_request(self,request):
            print('request  01')
            return HttpResponse('<h1>Middleware 01</h1>')
    
    class Middleware02(MiddlewareMixin):
        def process_request(self,request):
            print('request  02')
            return HttpResponse('<h1>Middleware 02</h1>')

    访问http://127.0.0.1:8000/index/,我们会看到如下:

    从上图我们可以看出,在执行到Middleware02后,该类的process_request返回了Httpresponse对象,下面的Middleware01和views没有被执行。

    示例三   一个没什么意义的示例

    修改Middleware_test.py文件内容如下:

    from django.utils.deprecation import MiddlewareMixin
    from django.shortcuts import HttpResponse
    class Middleware01(MiddlewareMixin):
        def process_request(self,request):
            print('request  01')
            return HttpResponse('<h1>Middleware 01</h1>')
    
    class Middleware02(MiddlewareMixin):
        def process_request(self,request):
            print('request  02')
            return HttpResponse('<h1>Middleware 02</h1>')
        def process_response(self,request,response):
            print('response 02')
            return response

    访问http://127.0.0.1:8000/index/,我们会看到如下:

    上图可以看出它与示例二的区别在于,在Middleware02中添加了process_response方法,该方法在process_request后被执行了。

    小结:

    middleware可以request请求到达django之后views之前,对request进行预处理。

    middleware需要在settints.py的MIDDLEWARE中注册激活,MIDDLEWARE是一个列表,middleware的执行顺序是MIDDLEWARE列表的索引顺序。

    process_request方法如果返回None,按MIDDLEWARE列表中的顺序执行完middleware后,到urls.py中匹配views,执行views。

    process_request方法如果返回Httpresponse,如果当前middleware中没有process_response方法,则从此处middleware一层一层向上返回。

    process_request方法如果返回Httpresponse,如果当前middleware中有process_response方法,则从当前middleware中process_response处一层一层向上返回。

    process_response

    process_response(request,response):views处理request后,返回HttpResponse对象。该方法可以对HttpResponse对象进行修改。

    参数:

    request:web服务器发来的wsgi request。

    response:HttpResponse对象。

    返回值:HttpResponse对象。

    接着上面的项目,调整Middleware_test.py文件。

    from django.utils.deprecation import MiddlewareMixin
    from django.shortcuts import HttpResponse
    
    class Middleware01(MiddlewareMixin):
        def process_request(self,request):
            print('request  01')
        def process_response(self,request,response):
            print('response 01')
            return response
    
    class Middleware02(MiddlewareMixin):
        def process_request(self,request):
            print('request  02')
        def process_response(self,request,response):
            print('response 02')
            return response

    上述这两个middleware什么都不做,只是打印下加载顺序。访问http://127.0.0.1:8000/index/

    示例一  修改默认输出

    我们通过process_response修改views的HttpResponse对象中的content内容。修改后的Middleware_test.py文件如下:

    from django.utils.deprecation import MiddlewareMixin
    from django.shortcuts import HttpResponse
    
    class Middleware01(MiddlewareMixin):
        def process_request(self,request):
            print('request  01')
        def process_response(self,request,response):
            print('response 01')
            return response
    
    class Middleware02(MiddlewareMixin):
        def process_request(self,request):
            print('request  02')
        def process_response(self,request,response):
            print('response 02')
            response.content = '<h1>Hello World, process_response</h1>'
            return response

    访问http://127.0.0.1:8000/index/,我们会看到如下:

    示例二  了解middle中HttpRespone的加载顺序。

    修改middleware_test.py中的内容如下:

    from django.utils.deprecation import MiddlewareMixin
    from django.shortcuts import HttpResponse
    
    class Middleware01(MiddlewareMixin):
        def process_request(self,request):
            print('request  01')
        def process_response(self,request,response):
            response.content = '<h1>process_response 01</h1>'
            return response
    
    class Middleware02(MiddlewareMixin):
        def process_request(self,request):
            print('request  02')
        def process_response(self,request,response):
            response.content = '<h1>process_response 02</h1>'
            return response

    访问http://127.0.0.1:8000/index/,我们会看到如下:

    下面我们把settings.py中Middleware01和Middleware02换一下位置。查看结果:

    我们发现结果发生了改变,因此我们可以得出如下结论:

    middleware可以对view返回的HttpResponse进行修改。

    HttpResponse的执行顺序是settings.py中MIDDLEWARE列表从最后一个元素(middleware)开始一直到第一个元素(middleware)结束。

    request和HttpResponse执行流程我们可以画一个简易图,如下:

    process_view

    process_view(request, view_func, view_args, view_kwargs):请求到来之后,view视图之前,可以改变参数的值来改变最终的输出结果。

    参数:

    request:web server发来的wsgi request(HttpRequest对象)。

    view_func:视图函数的内存地址。

    view_args:给view_func传递的位置参数(元组)。

    view_kwargs:给view_func传递的关键字参数(字典)。

    返回值:如果返回None,按照MIDDLEWARE的顺序执行其它middleware,直到运行响应的view视图。如果返回的是HttpResponse,则按照MIDDLEWARE的顺序从最后一个middleware开始倒叙执行。

    示例 一 

    查看process_view的执行顺序,修改middleware_test.py文件如下:

    from django.utils.deprecation import MiddlewareMixin
    from django.shortcuts import HttpResponse
    
    class Middleware01(MiddlewareMixin):
        def process_request(self,request):
            print('process_request  01')
        def process_view(self,request, view_func, view_args, view_kwargs):
            print('process_view  01')
        def process_response(self,request,response):
            print('process_response  01')
            return response
    
    class Middleware02(MiddlewareMixin):
        def process_view(self,request, view_func, view_args, view_kwargs):
            print('process_view  02')
        def process_request(self,request):
            print('process_request  02')
        def process_response(self,request,response):
            print('process_response  02')
            return response

    访问http://127.0.0.1:8000/index/,我们会看到如下:

    示例 二

    process_view修改关键字参数。

    在修改之前,我们需要调整下views.py中的index方法和urls.py中的路由,settings.py,middleware_test.py。

    views.py内容如下:

    from django.shortcuts import render
    
    # Create your views here.
    def index(request,server_id):
        # 打印修改后的server_id
        print('views function server_id:%s' %server_id)
        return render(request,'index.html')

    urls.py内容如下:

    from django.conf.urls import url
    from django.contrib import admin
    from . import views
    urlpatterns = [
        url(r'^admin/', admin.site.urls),
        url(r'^index/(?P<server_id>d+)/', views.index),
        # url(r'^index/', views.index),
    ]

    .middleware_test.py内容如下:

    from django.utils.deprecation import MiddlewareMixin
    
    class Middleware01(MiddlewareMixin):
        def process_view(self,request, view_func, view_args, view_kwargs):
            print(f'前端发来的server_id: {view_kwargs["server_id"]}' )
            view_kwargs['server_id'] = 100

    访问http://127.0.0.1:8000/index/,我们会看到如下:

    示例  二

    使用process_view返回HttpResponse。

    修改middleware_test.py文件内容如下:

    from django.utils.deprecation import MiddlewareMixin
    
    class Middleware01(MiddlewareMixin):
        def process_view(self,request, view_func, view_args, view_kwargs):
            print(f'前端发来的server_id: {view_kwargs["server_id"]}')
            return view_func(request,server_id=100)

    访问http://127.0.0.1:8000/index/,我们会看到如下:

    示例  三

    process_view执行后settings.py中MIDDLEWARE中的middleware加载顺序。

    修改middleware_test.py文件内容如下:

    from django.utils.deprecation import MiddlewareMixin
    
    class Middleware01(MiddlewareMixin):
        def process_response(self,request,response):
            print('process_response  01')
            return response
        def process_view(self,request, view_func, view_args, view_kwargs):
            print(f'前端发来的server_id: {view_kwargs["server_id"]}')
            return view_func(request,server_id=100)
    
    class Middleware02(MiddlewareMixin):
        def process_response(self,request,response):
            print('process_response  02')
            return response

    访问http://127.0.0.1:8000/index/,我们会看到如下:

    由上面三个示例小结如下:

    process_view在request到达django之后,view视图之前,提前对view进行预处理。

    如果process_view返回HttpReponse,将按settings.py中的MIDDLEWARE元素从最后一个middleware执行到第一个middleware。

    process_view可以修改关键字参数。

    process_exception

    process_exception(request, exception):view视图中抛出异常后,process_exception可以对异常进行后续处理。

    参数:

    request:web server发来的wsgi request(HttpRequest对象)。

    exception:view视图函数中引发的Exception对象。

    返回值:None或者是HttpResponse对象,如果是None是返回django默认异常处理,如果返回的是HTTPResponse是用户自定义的异常处理页面。

    示例   处理抛出的异常

    1、正常抛出异常

    修改view内容如下:

    from django.shortcuts import render
    
    # Create your views here.
    def index(request,server_id):
        # 抛出异常
        int('a')
        return render(request,'index.html')

    将settings.py中我们写的middleware先注释掉。访问http://127.0.0.1:8000/index/,我们会看到如下:

    上面的是正常情况的异常,下面我们对异常进行后续处理返回一个界面。

    修改middleware_test.py内容如下:

    from django.utils.deprecation import MiddlewareMixin
    from django.shortcuts import HttpResponse
    
    class Middleware01(MiddlewareMixin):
        def process_exception(self,request,exception):
            print(exception)
            return HttpResponse('<h1>发生了一个异常</h1>')

    访问http://127.0.0.1:8000/index/,我们会看到如下:

    小结:

    process_exception可以对view视图引发的异常进行后续处理。

    process_exception执行顺序按settings.py中的MIDDLEWARE元素从最后一个middleware执行到第一个middleware。

    process_template_response

    process_template_response(request, response):该方法在view执行完之后被执行,前提是view返回的是一个TemplateResponse对象,或者是一个由render方法的HttpResponse对象。如果不是这两种则不会被执行。

    参数:

    request:web server发来的wsgi request(HttpRequest对象)。

    response:TemplateResponse对象或者是带有reader方法的HttpResponse对象中。

    返回值:HttpResponse对象

    示例  使用process_template_response

    使用前我们需要修改view.py文件和middleware_test.py文件。

    view.py文件内容如下:

    from django.shortcuts import HttpResponse
    
    def index(request,server_id):
        '''
        因为process_template_response执行的前提是view必须返回TemplateResponse对象
        或者是HttpResponse对象中带有render方法,我们知道view视图函数必须返回HttpResponse对象
        所以我们先创建一个HttpResponse对象。
        在定义一个render方法,该方法是最终的输出结果,所以需要返回个HttpResponse对象
        在HttpResponse对象中添加方法render。
        这样在调用view视图函数后便会执行middleware中的process_template_response方法了
        :param request:
        :param server_id:
        :return:
        '''
        ret = HttpResponse("")
        def render():
            print("这里是自定义的render方法")
            return HttpResponse("<h1>Hello World</h1>")
    
        ret.render = render
        return ret

    middleware_test.py文件内容如下:

    from django.utils.deprecation import MiddlewareMixin
    
    class Middleware01(MiddlewareMixin):
        def process_template_response(self,request, response):
            print('process_template_response 被调用了')
            return response

    访问http://127.0.0.1:8000/index/,我们会看到如下:

    示例 二

    查看middleware中的执行顺序,修改middleware_test.py和settings.py文件

    middleware_test.py文件内容如下:

    from django.utils.deprecation import MiddlewareMixin
    
    class Middleware01(MiddlewareMixin):
        def process_template_response(self,request, response):
            print('process_template_response 被调用了')
            return response
        def process_response(self,request, response):
            print('process_response 01')
            return response
    
    class Middleware02(MiddlewareMixin):
        def process_response(self,request, response):
            print('process_response 02')
            return response

    访问http://127.0.0.1:8000/index/,我们会看到如下:

    小结:

    process_template_response该方法在view执行完之后被执行,前提是view返回的是一个TemplateResponse对象,或者是一个由render方法的HttpResponse对象。如果不是这两种则不会被执行。

    process_template_response执行完成后,按settings.py中的MIDDLEWARE最后一个middleware执行到第一个middleware。

    总结:

    process_response,process_view,process_exception,process_template_response返回的结果必须是一个HttpResponse对象。

    process_view,process_exception,process_template_response执行完成后,都会按照settings.py中MIDDLEWARE中注册的middleware倒叙执行(如果有process_response)process_response。

    process_request的执行顺序是按照settings.pyMIDDLEWARE中注册的先后顺序执行middleware。

    process_request返回None,则会正常执行其它middleware,路由匹配,执行view视图函数。

    process_request返回HttpResponse,则直接在当前middleware的位置倒叙向上执行process_response(如果middleware中有process_response)。

  • 相关阅读:
    js scrollTop到达指定位置!
    ajax图片加载,complete
    OpenShift 集群搭建指南
    net core ef code first 使用步骤
    Web Api Json 序列化 属性被加上 k__BackingField 解决办法
    [ASP.NET MVC 5 高级编程] 第4章 模型
    [ASP.NET MVC 5 高级编程] 第3章 视图
    [Java学习笔记] Java核心技术 卷1 第六章 接口与内部类
    [Java学习笔记] Java核心技术 卷1 第五章 继承
    [Java学习笔记] Java核心技术 卷1 第四章 对象与类
  • 原文地址:https://www.cnblogs.com/caesar-id/p/12897825.html
Copyright © 2011-2022 走看看