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

    中间件

    1,默认中间件

    • 中间件:Django中settings.py文件中的配置项,是Django默认自带的一些中间件

    • 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',
      ]
      
    • ​ MIDDLEWARE配置项是一个列表,列表中是一个个字符串,这些字符创其实是一个个类,也就是一个个中间件

    2,中间件的五个方法

    • process_request(self,request)
      (没有返回值,即返回值是None)
      (如果有返回值,则会直接返回浏览器)
      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)
      (必须有返回response)
      
    • 以上方法的返回值可以是一个None或者一个HTTPResponse对象,如果是None,则继续按照Django定义的规则向后继续执行,如果是HTTPresponse对象,则直接将该对象返回给用户

    • 当用户发起请求时,会依次经过所有的中间件,这个时候的请求process_request,最后到达视图函数views中,views处理后,在依次穿过中间件,这个时候是process_response,最后返回请求者

    • img

    1,process_request

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

    2,process_response

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

    • 必须返回response,不然你上层的中间件就没有拿到httpresponse对象,就会报错
      

    3,process_view

    • process_view(self, request, view_func, view_args, view_kwargs)
    • 该方法有四个参数,Django会在调用视图函数之前调用process_view方法
      • request是HttpRequest对象。
      • view_func是Django即将使用的视图函数。 (它是实际的函数对象,而不是函数的名称作为字符串。)
      • view_args是将传递给视图的位置参数的列表.
      • view_kwargs是将传递给视图的关键字参数的字典。 view_args和view_kwargs都不包含第一个视图参数(request)。
    • 它应该返回None或一个HttpResponse对象。 如果返回None,Django将继续处理这个请求,执行任何其他中间件的process_view方法,然后在执行相应的视图。 如果它返回一个HttpResponse对象,Django不会调用对应的视图函数。 它将执行中间件的process_response方法并将应用到该HttpResponse并返回结果。

    img

    4,process_exception

    • process_exception(self, request, exception)
    • 该方法两个参数:
      • 一个HttpRequest对象
      • 一个exception是视图函数异常产生的Exception对象。
    • 这个方法只有在视图函数中出现异常了才执行,它返回的值可以是一个None也可以是一个HttpResponse对象。如果是HttpResponse对象,Django将调用模板和中间件中的process_response方法,并返回给浏览器,否则将默认处理异常。如果返回一个None,则交给下一个中间件的process_exception方法来处理异常。它的执行顺序也是按照中间件注册顺序的倒序执行。
    • 如果视图函数中无异常,process_exception方法不执行。
    • img

    5,process_template_response(用的比较少)

    • process_template_response(self, request, response)

            它的参数,一个HttpRequest对象,response是TemplateResponse对象(由视图函数或者中间件产生)。

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

    • 视图函数执行完之后,立即执行了中间件的process_template_response方法,顺序是倒序,先执行MD2的,在执行MD1的,接着执行了视图函数返回的HttpResponse对象的render方法,返回了一个新的HttpResponse对象,接着执行中间件的process_response方法。

    3,自定义中间件

    • 自己写一个类,必须继承MiddlewareMixin

    • 步骤:

      • 在项目的应用文件夹下创建一个包,名字:例如:mymiddleware

      • 在包中创建一个py文件:例如:mymiddelware

      • mymiddleware.py

        • from diango.utils.deprecation import MiddlewareMixin
          
          class Md1(MiddlewareMixin):
          	def process_request(self, request):
          		print("Md1中的process_request")
          		
          	def process_reponse(self, request, response):
          		print("Md1中的process_response")
          		return response
          		
          		
          class Md2(MiddlewareMixin):
          	def process_request(self, request):
          		print("Md2中的process_request")
          		
          	def process_reponse(self, request, response):
          		print("Md2中的process_response")
          		return response
          		
          执行顺序:
          Md1请求
          Md2请求
          view函数...
          Md2返回
          Md1返回
          
    • 多个中间件中的process_response方法是按照MIDDLEWARE中的注册顺序倒序执行的,也就是说第一个中间件的process_request方法首先执行,而它的process_response方法最后执行,最后一个中间件的process_request方法最后一个执行,它的process_response方法是最先执行

    img

    • 自定义中间件应用

      • session登录认证,

        • class M1(MiddlewareMixin):
          
              def process_request(self,request):
          
                  #设置路径白名单,只要访问的是login登陆路径,就不做这个cookie认证
                  if request.path not in [reverse('login'),]:
                      print('我是M1中间件') #客户端IP地址
                      # return HttpResponse('sorry,没有通过我的M1中间件')
                      is_login = request.COOKIES.get('is_login', False)
          
                      if is_login:
                          pass
                      else:
                          # return render(request,'login.html')
                          return redirect(reverse('login'))
                  else:
                      return None #别忘了return None,或者直接写个pass
          
              def process_response(self,request,response):
          
                  print('M1响应部分')
                  # print(response.__dict__['_container'][0].decode('utf-8'))
                  return response
                  # return HttpResponse('瞎搞')
          
      • ip访问频率限制:某些ip访问服务器频率过高,进行拦截

      • url访问过滤:

        • 如果用户访问的是login视图,放过,即将login加入白名单
        • 如果访问其他视图,需要检测是不是有session认证,已经有了放行,没有返回login,这样就省的在每个视图函数上面写装饰器了

    4,Django生命周期

    img

    5,访问限制

    • import time
      from django.utils.deprecation import MiddlewareMixin
      from django.shortcuts import HttpResponse
      # 访问IP池
      visit_ip_pool = {}
      class RequestBlockingMiddleware(MiddlewareMixin):
          def process_request(self,request):
              # 获取访问者IP
              ip=request.META.get("REMOTE_ADDR")
              # 获取访问当前时间
              visit_time=time.time()
              # 判断如果访问IP不在池中,就将访问的ip时间插入到对应ip的key值列表,如{"127.0.0.1":[时间1]}
              if ip not in visit_ip_pool:
                  visit_ip_pool[ip]=[visit_time]
                  return None
              # 然后在从池中取出时间列表
              history_time = visit_ip_pool.get(ip)
              # 循环判断当前ip的时间列表,有值,并且当前时间减去列表的最后一个时间大于60s,把这种数据pop掉,这样列表中只有60s以内的访问时间,
              while history_time and visit_time-history_time[-1]>60:
                  history_time.pop()
              # 如果访问次数小于10次就将访问的ip时间插入到对应ip的key值列表的第一位置,如{"127.0.0.1":[时间2,时间1]}
              print(history_time)
              if len(history_time)<10:
                  history_time.insert(0, visit_time)
                  return None
              else:
                  # 如果大于10次就禁止访问
                  return HttpResponse("访问过于频繁,还需等待%s秒才能继续访问"%int(60-(visit_time-history_time[-1])))
      
    希望你眼眸有星辰,心中有山海,从此以梦为马,不负韶华
  • 相关阅读:
    BufferedImage学习记录一
    response总结一
    Externalizable接口
    request 总结一
    处理jsp显示文字过长问题
    验证码设计
    ORA01461: 仅能绑定要插入 LONG 列的 LONG 值
    MAP平台在单据中填写好部门后,关闭后重新打开,部门就没有了
    MAP平台设置节点选取范围
    MAP平台java.lang.StackOverflowError
  • 原文地址:https://www.cnblogs.com/daviddd/p/12049621.html
Copyright © 2011-2022 走看看