一、中间件简介

中间件就是介于请求和响应处理之间的一道处理过程,相对比较轻量级,并且在全局上改变Django的输入与输出,所以需要谨慎使用。

也就是说中间件帮助我们在视图函数执行之前和执行之后都可以做一些额外的操作,它本质是一个自定义类,类中定义了一些方法,Django框架会在请求的特定时间去执行这些方法。

在Settings.py文件中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',
]

二、自定义中间件

因为中间件是我们自己定义的类,所以它主要可以定义四个方法:

这五个方法的返回值可以是None也可以是一个HTTPResponse对象,如果是None,则继续按照Django定义的规则向后继续执行,如果是HTTPResponse对象,则直接将改对象返回给用户

process_request(self,request)	# 主要用的

process_response(self, request, response)	# 主要用的

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

process_exception(self, request, exception)

示例:

1、在项目中创建一个包,名字自定义,在创建一个py文件,名字自定义,例如:AuthenMD.py

from django.utils.deprecation import MiddlewareMixin


class MD1(MiddlewareMixin):

    # 请求来了先执行它,在到urls.py
    def process_request(self, request):
        print('MD1的 process_request 操作')

    # 响应的数据要先执行它,在到wsgi.py封装发送
    def process_response(self, request, response):
        print('MD1的 process_response 操作')
        return response

2、在Settings.py文件中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',

    # 添加自定义中间件配置
    'app01.AuthenMD.MD1',	 # 路径项目app01/AuthenMD.py文件中的MD1类
]

三、常用中间件方法

在中间件中最常用和最主要的方法是process_request和process_response

process_request

process_request(self, request)

process_request有一个参数—>request

request:和视图函数中的request是一样的。

它的返回值可以是None亦可以是HTTPResponse对象。

None:按照正常流程继续走,交给下一个中间件处理。

HTTPResponse对象:Django将不执行视图函数,而将相应的对象返回 给浏览器。

from django.utils.deprecation import MiddlewareMixin

class MD1(MiddlewareMixin):

    # 请求来了先执行它,在到urls.py和视图
    def process_request(self, request):
        print('MD1的 process_request 操作')

注意:

  1. 中间件的process_request方法是在执行视图函数之前执行的。
  2. 当配置多个中间件时,会按照MIDDLEWARF中的注册顺序,也就是列表的索引值,从前到后依次执行。
  3. 不同中间件之间传递的request都是同一个对象

process_response

process_response(self, request, response)

process_response有两个参数—>request,response

request:和视图函数中request一样。

response:是视图函数返回的HTTPResponse对象。

该方法的返回值必须是HTTPResponse对象

通常都是返回response

from django.utils.deprecation import MiddlewareMixin

class MD1(MiddlewareMixin):

    # 请求来了先执行它,在到urls.py和视图
    def process_request(self, request):
        print('MD1的 process_request 操作')
        # 不必写return,默认返回None

    # 视图执行后执行它,在到wsgi.py封装发送
    def process_response(self, request, response):	# 两个参数必须有,名字自定义
        print('MD1的 process_response 操作')
        return response		# 必须有返回值,返回response就向接力棒一样,随便写返回内容就会被替代

注意:

  1. process_response方法是在视图函数之后执行的。
  2. 多个中间件中的process_response方法是按照MIDDLEWARE中的注册顺序倒序执行的。

process_view

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

process_view有四个参数:

request:是HTTPResponse对象

view_func:是Django即将使用的视图函数。(实际的函数对象)

view_args:是将传递给视图的位置参数的列表(不包含request)

view_kwargs:是将传递给视图的关键字参数的字典。(不包含request)

返回None或者一个HTTPResponse对象

None:Django将继续处理这个请求,执行其他中间件的process_view方法和相应的视图。

HTTPResponse对象:Django不会调用对应的函数,他将直接执行中间件中的process_response方法,并将应用到改HTTPResponse并返回结果

from django.utils.deprecation import MiddlewareMixin
from django.http import HttpResponse


class MD1(MiddlewareMixin):

    def process_request(self, request):
        print('MD1的 process_request 操作')

    def process_response(self, request, response):
        print('MD1的 process_response 操作')
        return response

    # Django会在调用视图函数之前调用process_view方法
    def process_view(self, request, view_func, view_args, view_kwargs):
        print('MD1的 process_view 操作')

# 输出
MD1的 process_request 操作
MD1的 process_view 操作
视图 login 操作
MD1的 process_response 操作

注意:

  1. process_view方法是在process_request方法之后,process_response之前,视图函数之前执行的。
  2. 执行顺序是按照MIDDLEWARE中的注册顺序从前到后顺序执行的

process_exception

process_exception(self, request, exception)

改方法有两个参数:

request:一个HTTPResponse对象

exception:视图函数异常产生的Exception对象。

返回None或者一个HTTPResponse对象

None:则交给下一个中间件的process_exception方法来处理

HTTPResponse对象:Django将调用模板和中间件中的process_response方法,并返回给浏览器,否则默认处理异常。

from django.utils.deprecation import MiddlewareMixin

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('MD1的 process_view 操作')

    def process_exception(self, request, exception):
        print('MD1的 process_exception 执行了,——>视图函数出错了')


# 输出
MD1的 process_request 操作
MD1的 process_view 操作
MD1的 process_exception 执行了,——>视图函数出错了
MD1的 process_response 操作

注意:

process_exception方法是在视图函数出现了错误才执行的,否则是不执行的。

四、中间件版登录认证

views.py文件

from django.shortcuts import render, redirect


def login(request):
    if request.method == 'GET':
        return render(request, 'login.html')
    else:
        name = request.POST.get('uname')
        pwd = request.POST.get('pwd')
        if name == 'xiaoyang' and pwd == '123':
            request.session['is_login'] = 'True'
            return redirect('index')
        else:
            return redirect('login')


def index(request):
    return render(request, 'index.html')


def quit(request):
    request.session.flush()     # 删除sessionid,服务端和浏览器都删除
    return render(request, 'login.html')

AuthenDM.py 中间件文件

from django.utils.deprecation import MiddlewareMixin
from django.shortcuts import redirect

# 白名单,白名单中的不需要验证session
WHITE_LIST = [
    '/login/'
]

class MD1(MiddlewareMixin):

    def process_request(self, request):
        if request.path in WHITE_LIST:  # 地址在白名单中就放行
            return
        else:
            # 不在白名单中就判断session
            is_login = request.session.get('is_login')
            if is_login == 'True':      # 登录了就放行
                return
            else:                       # 没登录就直接跳转到登录页面
                return redirect('login')
06-27 22:00