• python 终极篇 ---- 中间件


    中间件------------------------>>>>>>>>>>>>>
        中间件是一个用来处理django的响应与请求的框架级别的钩子.它是一个轻量,低级别的插件系统,
        用于在全局范围内改变django的输入和输出,每个中间件组件都负责做一些特定的功能.
        
        ----简单来说,Django的中间件是一个类。用来在全局范围内处理请求和响应。
        
        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)
        
        1. process_request
            1. 执行时间
                在视图函数之前执行
            2. 参数
                request 和视图中的request是同一个
            3. 返回值
                返回None  
                返回response对象   
                    不执行后面中间的process_request方法和视图
                    直接执行当前值中间件的process_response方法
            4. 执行顺序
                按照注册的顺序执行 
                
                
        2. process_response    
            1. 执行时间    
                在视图函数之后执行
            2. request, response
                request 和视图中的request是同一个
                response 返回的response对象
            3. 返回值
                返回response对象
            4. 执行顺序
                按照注册的倒序执行
        
        
        3. process_view
            1. 执行时间
                在视图函数之前,process_request之后执行
            2. 参数
                view_func  将要执行的视图函数
                view_args  视图函数的可变长位置参数
                view_kwargs    视图函数的可变长关键字参数
            3. 返回值
                返回  None  正常执行 
                返回  response对象   不执行后面的process_view和视图,直接执行所有中间件的process_response方法
                
            4。执行顺序
                按照注册的顺序执行
        
        4. process_exception(有条件触发:有错误才执行)
                    1. 执行时间
                        在视图函数之后,process_response之前执行
                    2. 参数
                        exception  错误对象
                    3. 返回值
                        返回  None  不对错误进行处理,交给下一个中间件进行处理
                        返回  response对象  下一个中间的process_exception不执行,直接执行所有中间件的process_response方法
                    4. 执行顺序
                        按照注册的倒序执行
        5. process_template_response(条件触发:视图返回的response有render方法)
            1. 执行时间
                在视图函数之后,process_response之前执行
            2. 参数
            3. 返回值
                返回 response对象
            4. 执行顺序
                按照注册的倒序执行,执行完所有的process_template_response方法后执行response.render方法
        

                            中间件的执行流程                           

    上一部分,我们了解了中间件中的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两个方法的触发是有条件的,执行顺序也是倒序。总结所有的执行流程如下:

     

     小练习:

    (1)

    AuthMD中间件注册后,所有的请求都要走AuthMD的process_request方法。

    如果URL在黑名单中,则返回This is an illegal URL的字符串;

    访问的URL在白名单内或者session中有user用户名,则不做阻拦走正常流程;

    正常的URL但是需要登录后访问,让浏览器跳转到登录页面。

    注:AuthMD中间件中需要session,所以AuthMD注册的位置要在session中间的下方。 

    from django.conf.urls import url
    from django.contrib import admin
    from app01 import views
    
    urlpatterns = [
        url(r'^admin/', admin.site.urls),
        url(r'^login/',views.login),
        url(r'^home/',views.home),
        url(r'^index/',views.index),
        url(r'^logout/',views.logout),
    ]
    urls
    from django.shortcuts import render,HttpResponse,redirect
    from django.conf import global_settings
    # Create your views here.
    
    def login(request):
        err_msg = ""
        if request.method == "POST":
            name = request.POST.get("name")
            pwd = request.POST.get("pwd")
            if name == "alex" and pwd == "123":
                request.session['user'] = "user"
                # request.session.set_expiry(0)   #设置关闭浏览器后自动注销
                return_path = request.GET.get("return","")
                if return_path:
                    return redirect(return_path)
                else:
                    return redirect("/home/")
    
            else:
                err_msg = "用户名或者密码错误"
        return render(request,"login.html",{"err_msg":err_msg})
    
    
    # 登陆装饰器
    # def wrap(func):
    #     def inner(request,*args,**kwargs):
    #         if request.session.get("is_login","") == "True":
    #             ret = func(request,*args,**kwargs)
    #             return ret
    #         else:
    #             path = request.path_info
    #             return redirect("/login/?return={}".format(path))
    #     return inner
    
    
    # @wrap
    def home(request):
        return render(request,"home.html")
    
    
    # @wrap
    def index(request):
        return render(request,"index.html")
    
    
    
    def logout(request):
        del request.session['user']
        return redirect("/login/")
    Views文件
    from django.utils.deprecation import MiddlewareMixin
    from django.shortcuts import HttpResponse, redirect, render
    
    
    class Login_middle(MiddlewareMixin):
        white_list = ["/login/", ]
        black_list = ["/black/", ]
    
        def process_request(self, request):
            path = request.path_info
            if path in self.black_list:
                return HttpResponse("这是黑名单的网址")
            elif path in self.white_list or request.session.get("user"):
                print(11)
                return
            else:
                print(22)
                return redirect("/login/?return={}".format(path))
    中间件
    'app01.my_middlewaremixin.Login_middle'
    settings注册中间件
    #login.html
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
    <form action="" method="post">
        {% csrf_token %}
        <p>用户名:<input type="text" name="name"></p>
        <p>密码:<input type="password" name="pwd"></p>
        <p><button>提交</button></p><span>{{ err_msg }}</span>
    </form>
    </body>
    </html>
    
    
    #index.html
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
    <h1>欢迎登陆index页面</h1>
    </body>
    </html>
    
    
    
    #home.html
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
    <h1>欢迎登陆home页面</h1>
    <a href="/logout/">注销</a>
    </body>
    </html>
    template文件 (三个)

    (2) 限制访问频率,一分钟只能访问3次.
        思路:根据IP做判断,1分钟只能访问3次
              1. 获取ip
              2. 记录时间
              3. 根据访问记录做判断
     

    import time
    
    l = {}
    class Throttle(MiddlewareMixin):
        def process_request(self, request):
    
            ip = request.META.get("REMOTE_ADDR")
            now = time.time()
            if not l.get(ip, ""):
                l[ip] = []
            history = l[ip]
            x = []
            for i in history:
                if now - i < 5:
                    x.append(i)
                    print(x)
            history = x
            print(history)
            if len(history) >= 3:
                return HttpResponse("次数太多了")
            history.insert(0, now)
            l[ip] = history
    中间件代码
    request.META 可以获取到所有内容,可以从中找你想用的东西.一组组键值对儿
    # {'ALLUSERSPROFILE': 'C:\ProgramData',
    #  'APPDATA': 'C:\Users\zhanghutao\AppData\Roaming',
    #  'COMMONPROGRAMFILES': 'C:\Program Files\Common Files',
    #  'COMMONPROGRAMFILES(X86)': 'C:\Program Files (x86)\Common Files',
    #  'COMMONPROGRAMW6432': 'C:\Program Files\Common Files',
    #  'COMPUTERNAME': 'DESKTOP-30PDHUE',
    #  'COMSPEC': 'C:\WINDOWS\system32\cmd.exe',
    #  'DJANGO_SETTINGS_MODULE': '中间件.settings',
    #  'HOMEDRIVE': 'C:', 'HOMEPATH': '\Users\zhanghutao',
    #  'LOCALAPPDATA': 'C:\Users\zhanghutao\AppData\Local',
    #  'LOGONSERVER': '\\DESKTOP-30PDHUE',
    #  'MOZ_PLUGIN_PATH': 'E:\Foxit Reader\plugins\',
    #  'NUMBER_OF_PROCESSORS': '4',
    #  'ONEDRIVE': 'C:\Users\zhanghutao\OneDrive',
    #  'OS': 'Windows_NT',
    #  'PATH': 'C:\WINDOWS\system32;'
    # 'C:\WINDOWS;'
    # 'C:\WINDOWS\System32\Wbem;'
    #  'C:\WINDOWS\System32\WindowsPowerShell\v1.0\;'
    #          'C:\Program Files\WIDCOMM\Bluetooth Software\;C:\Program Files\WIDCOMM\Bluetooth Software\syswow64;D:\mysql\mysql-5.7.23-winx64\bin;;D:\PPB\PBB Reader\x64;D:\python3.6\Scripts\;D:\python3.6\;C:\Users\zhanghutao\AppData\Local\Microsoft\WindowsApps;;D:\python3.6\lib\site-packages\pywin32_system32;D:\python3.6\lib\site-packages\pywin32_system32', 'PATHEXT': '.COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH;.MSC', 'PROCESSOR_ARCHITECTURE': 'AMD64', 'PROCESSOR_IDENTIFIER': 'Intel64 Family 6 Model 58 Stepping 9, GenuineIntel', 'PROCESSOR_LEVEL': '6', 'PROCESSOR_REVISION': '3a09', 'PROGRAMDATA': 'C:\ProgramData', 'PROGRAMFILES': 'C:\Program Files', 'PROGRAMFILES(X86)': 'C:\Program Files (x86)', 'PROGRAMW6432': 'C:\Program Files', 'PSMODULEPATH': 'C:\Program Files\WindowsPowerShell\Modules;C:\WINDOWS\system32\WindowsPowerShell\v1.0\Modules;C:\Program Files\Intel\Wired Networking\', 'PUBLIC': 'C:\Users\Public', 'PYCHARM_HOSTED': '1', 'PYCHARM_MATPLOTLIB_PORT': '54693', 'PYTHONIOENCODING': 'UTF-8', 'PYTHONPATH': 'D:\pycharm\PyCharm 2018.1.3\helpers\pycharm_matplotlib_backend;D:\PythonTest\django项目\中间件', 'PYTHONUNBUFFERED': '1', 'SESSIONNAME': 'Console', 'SYSTEMDRIVE': 'C:', 'SYSTEMROOT': 'C:\WINDOWS', 'TEMP': 'C:\Users\ZHANGH~1\AppData\Local\Temp', 'TMP': 'C:\Users\ZHANGH~1\AppData\Local\Temp', 'USERDOMAIN': 'DESKTOP-30PDHUE', 'USERDOMAIN_ROAMINGPROFILE': 'DESKTOP-30PDHUE', 'USERNAME': 'zhanghutao', 'USERPROFILE': 'C:\Users\zhanghutao', 'WINDIR': 'C:\WINDOWS', 'RUN_MAIN': 'true', 'SERVER_NAME': 'DESKTOP-30PDHUE', 'GATEWAY_INTERFACE': 'CGI/1.1', 'SERVER_PORT': '8000', 'REMOTE_HOST': '', 'CONTENT_LENGTH': '', 'SCRIPT_NAME': '', 'SERVER_PROTOCOL': 'HTTP/1.1', 'SERVER_SOFTWARE': 'WSGIServer/0.2', 'REQUEST_METHOD': 'GET', 'PATH_INFO': '/index/', 'QUERY_STRING': '',
    #  'REMOTE_ADDR': '127.0.0.1',
    #  'CONTENT_TYPE': 'text/plain',
    #  'HTTP_HOST': '127.0.0.1:8000',
    #  'HTTP_CONNECTION': 'keep-alive', 'HTTP_UPGRADE_INSECURE_REQUESTS': '1', 'HTTP_USER_AGENT': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.170 Safari/537.36', 'HTTP_ACCEPT': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8', 'HTTP_ACCEPT_ENCODING': 'gzip, deflate, br', 'HTTP_ACCEPT_LANGUAGE': 'zh-CN,zh;q=0.9', 'HTTP_COOKIE': 'csrftoken=HSERiDbpYwWLfLhrjDIgcsMP8HjD1CqXuSPjgSD40l8YpqbMPTYaNKl3xm6MLWne; sessionid=qfrad5a76h2ozt0erj74wef1nrzsl63n', 'wsgi.input': <_io.BufferedReader name=964>, 'wsgi.errors': <_io.TextIOWrapper name='<stderr>' mode='w' encoding='UTF-8'>, 'wsgi.version': (1, 0), 'wsgi.run_once': False, 'wsgi.url_scheme': 'http', 'wsgi.multithread': True, 'wsgi.multiprocess': False, 'wsgi.file_wrapper': <class 'wsgiref.util.FileWrapper'>, 'CSRF_COOKIE': 'HSERiDbpYwWLfLhrjDIgcsMP8HjD1CqXuSPjgSD40l8YpqbMPTYaNKl3xm6MLWne'}
    例如:
  • 相关阅读:
    != 比 & 的优先级高
    VC++ 报错:Heap corruption detected
    sqlite 查询数据库中所有的表名,判断某表是否存在,将某列所有数值去重后获得数量
    Unicode与UTF-8,UTF-16
    各种格式的压缩包解压,7zip 命令行
    bat批处理文件运行时隐藏cmd窗口
    标准库中 vector list等排序
    duilib 实现列表头任意拖动
    duilib 实现 XML重用(item完全重合的CList)
    C++-POJ2503-Babelfish[hash]
  • 原文地址:https://www.cnblogs.com/dalaoban/p/9699675.html
Copyright © 2020-2023  润新知