10.django中间件

一、中间件简介

中间件就是介于request和response处理之间的一道处理过程,相对比较轻量级,在全局上改变django的输入与输出,因为改变的是全局,所以要谨慎使用。

中间件其实就是在我们视图函数执行前执行的一些额外的操作,本质上就是自定义一个类,定义了一些方法,我们的django项目一直都是使用中间件的,打开setting.py文件

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',
    # 自定义中间件
    'app01.utils.mymiddleware.DM1',
    'app01.utils.mymiddleware.SeesiongAuth',
]

最后两条是我们自定义的中间件,MIDDLEWARE配置项是一个列表,列表元素是一个个字符串,也是一个个中间件。

image-20200916161516499

中间件中可以写五个方法,

二、自定义中间件

1、中间件中可以定义的方法

开源中国上有关中间件的解释

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

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

以上方法的返回值是一个None或者一个HttpResponse对象,则直接将该对象返回给用户。

2、自定义中间件

在项目中创建一个包,一般以utils作为包名,表示一个公用的组件,创建一个py文件。

from django.utils.deprcation import MiddlewareMixin

# 自定义的中间不是一定要有这两个方法
class DM1(MiddlewareMixin):
    def process_request(self, request):
        print("MD1请求")
        return None

    def process_response(self, request, response):
        print('MD1响应')
        return response

3、中间件中的方法

1)process_request

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

2)process_response

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

process_response方法实在视图函数之后执行的,多个中间件的process_response方法是按照MIDDLEWARE中注册顺序倒序执行的,也就是说第一个中间件的request方法先执行,response方法最后执行。

image-20200916191115913

# 中间件个方法的执行顺序
MD2里面的 process_request
MD1里面的 process_request
app01 中的 index视图
MD1里面的 process_response
MD2里面的 process_response

3)process_view

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

参数:

  • request是HttRequest对象,
  • 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并返回结果。

image-20200916192420547

4)process_exception

process_exception(self, request, exception)

参数:

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

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

image-20200916193011255

5)process_template_response

process_template_response(self, request, response)

参数:

  • 一个HttpRequest对象,
  • response是TemplateResponse对象(由视图函数或中间件产生)

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

3、中间件的执行顺序

image-20200916173721372

中间的执行顺序是按照MIDDLEWARE列表中定义的顺序来执行的(红色箭头标识的),即请求最后一个经过的中间件是该请求对应响应的第一个中间件。

请求对应的是process_request()方法,响应对应的是process_response()方法。

三、中间件白名单

# 自定义中间件.py
from django.urls import reverse


class SeesiongAuth(MiddlewareMixin):
    def process_request(self, request):
        # 设置白名单, reverse别名反向解析
        white_list = [reverse('login'), '/home/']
        if request.path in white_list:
            return None
        is_login = request.session.get('is_login')
        if is_login is True:
            return None
        else:
            return redirect('login')

如果不设置白名单,这种写法导致浏览器向服务器发送请求,服务器判断sessionid发现其为空,重定向到login页面导致其重新判断sessionid的值,重定向多次,所以要设置白名单

四、中间件版登陆验证

# urls.py
from django.conf.urls import url
from app01 import views

urlpatterns = [
    url(r'^index/$', views.index),
    url(r'^login/$', views.login, name='login'),
]
# views.py
from django.shortcuts import render, HttpResponse, redirect


def index(request):
    return HttpResponse('this is index')


def home(request):
    return HttpResponse('this is home')


def login(request):
    if request.method == "POST":
        user = request.POST.get("user")
        pwd = request.POST.get("pwd")

        if user == "Q1mi" and pwd == "123456":
            # 设置session
            request.session["user"] = user
            # 获取跳到登陆页面之前的URL
            next_url = request.GET.get("next")
            # 如果有,就跳转回登陆之前的URL
            if next_url:
                return redirect(next_url)
            # 否则默认跳转到index页面
            else:
                return redirect("/index/")
    return render(request, "login.html")
# login.html
from django.shortcuts import render, HttpResponse, redirect


def index(request):
    return HttpResponse('this is index')


def home(request):
    return HttpResponse('this is home')


def login(request):
    if request.method == "POST":
        user = request.POST.get("user")
        pwd = request.POST.get("pwd")

        if user == "Q1mi" and pwd == "123456":
            # 设置session
            request.session["user"] = user
            # 获取跳到登陆页面之前的URL
            next_url = request.GET.get("next")
            # 如果有,就跳转回登陆之前的URL
            if next_url:
                return redirect(next_url)
            # 否则默认跳转到index页面
            else:
                return redirect("/index/")
    return render(request, "login.html")
# middlewares.py
class AuthMD(MiddlewareMixin):
    white_list = ['/login/', ]  # 白名单
    balck_list = ['/black/', ]  # 黑名单

    def process_request(self, request):
        from django.shortcuts import redirect, HttpResponse

        next_url = request.path_info
        print(request.path_info, request.get_full_path())

        if next_url in self.white_list or request.session.get("user"):
            return
        elif next_url in self.balck_list:
            return HttpResponse('This is an illegal URL')
        else:
            return redirect("/login/?next={}".format(next_url))
# setting.py注册
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',
    'middlewares.AuthMD',
]

五、中间件案例

应用案例:

1、做IP访问频率限制(可以防止爬虫)

2、URL过滤(白名单)

posted @ 2020-09-28 21:17  journeyerxxx  阅读(163)  评论(0编辑  收藏  举报
返回顶部