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

    一、什么是中间件

    中间件是一个用来处理Django的请求和响应的框架级别的钩子。它是一个轻量、低级别的插件系统,用于在全局范围内改变Django的输入和输出。每个中间件组件都负责做一些特定的功能。

    但是由于其影响的是全局,所以需要谨慎使用,使用不当会影响性能。

    二、自定义中间件

    中间件可以定义五个方法

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

    自己定义一个中间件,需要写一个类,这个类必须继承 MiddlewareMixin

    # views.py
    
    def index(request):
        print("views.py(视图函数)")
        return HttpResponse("ok")
    # my_middleware.py
    
    from django.utils.deprecation import MiddlewareMixin
    
    
    class Test1Middleware(MiddlewareMixin):
    
        def process_request(self, request):
            print("Test1请求")
    
        def process_response(self, request, response):
            print("Test1返回")
            return response
    
    
    class Test2Middleware(MiddlewareMixin):
    
        def process_request(self, request):
            print("Test2请求")
    
        def process_response(self, request, response):
            print("Test2返回")
            return response

    结果:

    Test1请求
    Test2请求
    views.py(视图函数)
    Test2返回
    Test1返回

    注意:

    如果当请求到达 Test2请求 的时候直接不符合条件返回,即 return HttpResponse("Test2Middleware中断"),程序将把请求直接发给中间件 Test2Middleware 返回,然后依次返回到请求者:

    from django.utils.deprecation import MiddlewareMixin
    from django.shortcuts import HttpResponse
    
    class Test1Middleware(MiddlewareMixin):
        ...
    
    class Test2Middleware(MiddlewareMixin):
    
        def process_request(self, request):
            print("Test2请求")
            return HttpResponse("Test2Middleware中断")
        ...

    结果:

    Test1请求
    Test2请求
    Test2返回
    Test1返回

    process_request

    该方法有一个参数,就是request。它的返回值可以是None也可以是HttpResponse对象。返回值是None的话,按正常流程继续走,交给下一个中间件处理,如果是HttpResponse对象,Django将不执行视图函数,而将相应对象直接返回给浏览器。

    process_response

    该方法有两个参数,一个是request,一个是response,request就是上述例子中一样的对象,response是视图函数返回的HttpResponse对象。该方法的返回值也必须是HttpResponse对象。

    process_view

    该方法有四个参数;

    request      HttpRequest对象
    view_func    Django即将使用的视图函数(它是实际的函数对象,而不是函数的名称作为字符串)
    view_args    将传递给视图的位置参数的列表
    view_kwargs  将传递给视图的关键字参数的字典;view_args和view_kwargs都不包含第一个视图参数(request)

    class Test1Middleware(MiddlewareMixin):
    
        def process_request(self, request):
            print("Test1请求")
    
        def process_response(self, request, response):
            print("Test1返回")
            return response
    
        def process_view(self, request, view_func, view_args, view_kwargs):
            print("Test1_view")
    
    
    class Test2Middleware(MiddlewareMixin):
    
        def process_request(self, request):
            print("Test2请求")
    
        def process_response(self, request, response):
            print("Test2返回")
            return response
    
        def process_view(self, request, view_func, view_args, view_kwargs):
            print("Test2_view")

    结果:

    Test1请求
    Test2请求
    Test1_view
    Test2_view
    views.py(视图函数)
    Test2返回
    Test1返回

    process_exception

    该方法两个参数;

    request      HttpRequest对象
    exception    视图函数异常产生的Exception对象

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

    process_template_response(用的比较少)

    该方法两个参数;

    request      HttpRequest对象
    response     TemplateResponse对象(由视图函数或者中间件产生)

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

    class MD1(MiddlewareMixin):
    
        def process_request(self, request):
            print("MD1里面的 process_request")
    
        def process_response(self, request, response):
            print("MD1里面的 process_response")
            return response
    
        def process_view(self, request, view_func, view_args, view_kwargs):
            print("-" * 80)
            print("MD1 中的process_view")
            print(view_func, view_func.__name__)
    
        def process_exception(self, request, exception):
            print(exception)
            print("MD1 中的process_exception")
            return HttpResponse(str(exception))
    
        def process_template_response(self, request, response):
            print("MD1 中的process_template_response")
            return response
    
    
    class MD2(MiddlewareMixin):
        def process_request(self, request):
            print("MD2里面的 process_request")
            pass
    
        def process_response(self, request, response):
            print("MD2里面的 process_response")
            return response
    
        def process_view(self, request, view_func, view_args, view_kwargs):
            print("-" * 80)
            print("MD2 中的process_view")
            print(view_func, view_func.__name__)
    
        def process_exception(self, request, exception):
            print(exception)
            print("MD2 中的process_exception")
    
        def process_template_response(self, request, response):
            print("MD2 中的process_template_response")
            return response
    View Code
    def index(request):
        print("app01 中的 index视图")
    
        def render():
            print("in index/render")
            return HttpResponse("O98K")
        rep = HttpResponse("OK")
        rep.render = render
        return rep
    views.py
    MD2里面的 process_request
    MD1里面的 process_request
    --------------------------------------------------------------------------------
    MD2 中的process_view
    <function index at 0x000001C111B97488> index
    --------------------------------------------------------------------------------
    MD1 中的process_view
    <function index at 0x000001C111B97488> index
    app01 中的 index视图
    MD1 中的process_template_response
    MD2 中的process_template_response
    in index/render
    MD1里面的 process_response
    MD2里面的 process_response
    结果

    三、应用案例

    ①做IP访问频率限制

    某些IP访问服务器的频率过高,进行拦截,比如限制每分钟不能超过20次。

    ②URL访问过滤

    如果用户访问的是login视图(放行);

    如果访问其他视图,需要检测是不是有session认证,已经有了放行,没有返回login,这样就省得在多个视图函数上写装饰器了!

    中间件版登录校验

    urls.py

    from django.conf.urls import url
    from appxx import views
    
    urlpatterns = [
        url(r'^index/', views.index),
        url(r'^home/', views.home),
        url(r'^login/', views.login),
    ]
    View Code

    views.py

    from django.shortcuts import HttpResponse
    from django.shortcuts import redirect
    from appxx import models
    
    
    def login(request):
        if request.method == "POST":
            user = request.POST.get("username")
            pwd= request.POST.get("password")
            obj = models.UserInfo.objects.filter(username=user, password=pwd)
            if obj:
                request.session["user"] = user
                request.session.set_expiry(30)  # session会在30秒数后失效
                next_url = request.GET.get("next")
                if next_url:
                    return redirect(next_url)
                else:
                    return redirect("/home/")
        return render(request, "login.html")
    
    
    def index(request):
        return HttpResponse("This's index.html.")
    
    
    def home(request):
        return HttpResponse("This's home.html.")
    View Code

    my_middleware.py

    from django.utils.deprecation import MiddlewareMixin
    from django.shortcuts import HttpResponse
    from django.shortcuts import redirect
    
    
    class CheckLoginMiddleware(MiddlewareMixin):
        white_list = ["/login/"]
        black_list = ["/black/"]
    
        def process_request(self, request):
            next_nrl = request.path_info
            if next_nrl in self.white_list or request.session.get("user"):
                return  # 只写return,相当于结束一个函数的继续
            elif next_nrl in self.black_list:
                return HttpResponse("This's an illegal URL.")
            else:
                return redirect("/login/?next={}".format(next_nrl))
    View Code

    login.html

    <!DOCTYPE html>
    <html lang="zh-cn">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
    <form action="{{ request.get_full_path }}" method="post">
        {% csrf_token %}
        <p>
            <label for="username">账号:</label>
            <input type="text" id="username" name="username">
        </p>
        <p>
            <label for="password">密码:</label>
            <input type="password" id="password" name="password">
        </p>
        <p>
            <label for="submit"></label>
            <input type="submit" value="登录">
        </p>
    </form>
    </body>
    </html>
    View Code

    CheckLoginMiddleware 中间件祖册后,所有的请求都要走 CheckLoginMiddleware 的 process_request 方法;访问的URL在白名单内或者 session 中有 xxx 用户名,则不做阻拦,走正常流程;如果URL在黑名单中,则返回 "This's an illegal URL." 的字符串;其他正常的URL如果需要登录后才能访问,则让浏览器跳转到登录页面。

  • 相关阅读:
    Redis(三)、Redis主从复制
    Redis(二)、Redis持久化RDB和AOF
    Redis(一)、Redis五种数据结构
    docker(部署常见应用):docker部署redis
    docker(三):Harbor 1.8.0 仓库的安装和使用
    Redis List 命令技巧
    数据库——MySQL——事务
    数据库——MySQL
    数据库——MySQL——权限管理
    数据库——MySQL——多表查询
  • 原文地址:https://www.cnblogs.com/believepd/p/9940105.html
Copyright © 2011-2022 走看看