python基础十 中间件

中间件介绍

中间件顾名思义,是介于request与response处理之间的一道处理过程,相对比较轻量级,并且在全局上改变django的输入与输出。因为改变的是全局,所以需要谨慎实用,用不好会影响到性能。

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',
]

django请求的声明周期

img


自定义中间件

中间件可以定义五个方法,分别是:(主要的是process_request和process_response)

  • 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)

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

img

自定义中间件

项目下自定义包: utils
创建py文件: middlewares.py
middlewares.py写代码
 # middlewares.py:
 from django.utils.deprecation import MiddlewareMixin

# 父类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
    
# 自定义中间件
class MD1(MiddlewareMixin):
    # process_request(self, request) 方法
    def process_request(self, request):
        print("MD1 中的process_request")

需要在setttings-->middleware中注册:

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',
    'utils.middlewares.MD1',
    'utils.middlewares.MD2',
]

process_request 方法

process_request有一个参数,就是request,这个request和视图函数中的request是一样的。

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

 # middlewares.py:
class MD1(MiddlewareMixin):
    def process_request(self, request):
        print("MD1 中的process_request")
        return None
# views.py
def index(request):
    print('index视图函数')
    return render(request, 'index.html')
# 打印结果
MD1 中的process_request
MD2 中的process_request
index视图函数

中间件的process_request方法是在执行视图函数之前执行的。

当配置多个中间件时,会按照MIDDLEWARE中的注册顺序,也就是列表的索引值,从前到后依次执行的。

不同中间件之间传递的request都是同一个对象

process_request中断
# middlewares.py:
class MD1(MiddlewareMixin):
    def process_request(self, request):
        print("MD1 中的process_request")
        return None

    def process_response(self, request, response):
        print("MD1里面的process_response")
        return HttpResponse(response)

    
class MD2(MiddlewareMixin):
    def process_request(self, request):
        print("MD2 中的process_request")
        return HttpResponse('MD2中断')  # return了httpresponse对象,那么会从你这个中间件类中的process_response方法开始执行返回操作,
    def process_response(self, request, response):
        print("MD2里面的process_response")
        return HttpResponse(response)
    
# 输出结果 
MD1 中的process_request
MD2 中的process_request
MD2里面的process_response
MD1里面的process_response    

process_response方法

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

 # middlewares.py:
class MD1(MiddlewareMixin):
    def process_request(self, request):
        print("MD1 中的process_request")
        return None

    def process_response(self, request, response):
        print("MD1里面的process_response")
        return HttpResponse(response)  # 必须有返回值,写return response 
    
 class MD2(MiddlewareMixin):
    def process_request(self, request):
        print("MD2 中的process_request")

    def process_response(self, request, response):
        print("MD2里面的process_response")
        return HttpResponse(response)  # 必须有返回值,写return response  
# 打印结果
MD1 中的process_request
MD2 中的process_request
index视图函数
MD2里面的process_response
MD1里面的process_response

多个中间件中的process_response方法是按照MIDDLEWARE中的注册顺序倒序执行的

基于session的身份认证

class MD1(MiddlewareMixin):
    def process_request(self, request):
        white_list = [reverse('login'),]
        print(request.path)
        if request.path in white_list:
            return None
        is_login = request.session.get('is_login')
        if is_login:
            return None
        else:
            return redirect(reverse('login'))

process_view

process_view(self, request, view_func, view_args, view_kwargs)

该方法有四个参数

request是HttpRequest对象。

view_func是Django即将使用的视图函数。 (它是实际的函数对象,而不是函数的名称作为字符串。)

view_args是将传递给视图的位置参数的列表.

view_kwargs是将传递给视图的关键字参数的字典。 view_args和view_kwargs都不包含第一个视图参数(request)。

Django会在调用视图函数之前调用process_view方法。它应该返回None或一个

HttpResponse对象。 如果返回None,Django将继续处理这个请求,执行任何其他中间件的process_view方法,然后在执行相应的视图。 如果它返回一个HttpResponse对象,Django不会调用对应的视图函数。 它将执行中间件的process_response方法并将应用到该HttpResponse并返回结果。

img

class MD1(MiddlewareMixin):
    def process_request(self, request):
        print("MD1 中的process_request")
        return None

    def process_response(self, request, response):
        print("MD1里面的process_response")
        return HttpResponse(response)

    def process_view(self, request, view_func, view_args, view_kwargs):
        print("MD1里面的process_view")



class MD2(MiddlewareMixin):
    def process_request(self, request):
        print("MD2 中的process_request")
        return None

    def process_response(self, request, response):
        print("MD2里面的process_response")
        return response

    def process_view(self, request, view_func, view_args, view_kwargs):
        print("MD2里面的process_view")
# 执行结果
MD1 中的process_request
MD2 中的process_request
MD1里面的process_view
MD2里面的process_view
index视图函数
[01/Aug/2019 19:20:06] "GET /index/ HTTP/1.1" 200 654
MD2里面的process_response
MD1里面的process_response

process_exception

process_exception(self, request, exception)

该方法两个参数:

​ 一个HttpRequest对象

​ 一个exception是视图函数异常产生的Exception对象。

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

        img


process_template_response(用的比较少)

process_template_response(self, request, response)

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

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

# views.py
def index(request):
    print("app01 中的 index视图")
  #raise ValueError('出错啦') 
    def render():
        print("in index/render")  
        #raise ValueError('出错啦') #至于render函数中报错了,那么会先执行process_template_response方法,然后执行process_exception方法,如果是在render方法外面报错了,那么就不会执行这个process_template_response方法了。
        return HttpResponse("O98K") #返回的将是这个新的对象
    rep = HttpResponse("OK")
    rep.render = render
    return rep

中间件的执行流程

求到达中间件之后,先按照正序执行每个注册中间件的process_reques方法,process_request方法返回的值是None,就依次执行,如果返回的值是HttpResponse对象,不再执行后面的process_request方法,而是执行当前对应中间件的process_response方法,将HttpResponse对象返回给浏览器。

img


中间件案例

1、做IP访问频率限制

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

2、URL访问过滤

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

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


posted @ 2019-08-25 12:17  Pyter  阅读(130)  评论(0)    收藏  举报