Django – 中间件

  • A+
所属分类:Python教程 学编程

一、说明

1.1、什么是中间件

官方的说法:中间件是一个用来处理Django的请求和响应的框架级别的钩子。它是一个轻量、低级别的插件系统,用于在全局范围内改变Django的输入和输出。每个中间件组件都负责做一些特定的功能。

但是由于其影响的是全局,所以需要谨慎使用,使用不当会影响性能。

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

1.2、中间配置介绍

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

MIDDLEWARE配置项是一个列表,列表中是一个个字符串,这些字符串其实是一个个类,也就是一个个中间件。

我们之前已经接触过一个csrf相关的中间件了。接下来就学习中间件中的方法以及这些方法什么时候被执行。

二、自定义中间件

中间件可以定义五个方法,分别是:(主要的是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)

以上方法的返回值可以是None或一个HttpResponse对象,如果是None,则继续按照django定义的规则向后继续执行,如果是HttpResponse对象,则直接将该对象返回给用户。

2.1、中间件的执行顺序说明:

按照注册的顺序(在settings.py里面设置中 从上到下的顺序)

用户请求 --> wsgi(建立socket和接收与响应HTTP请i去)--> process_request中间件(如果有响应则直接返回响应不向后执行,没响应继续向后执行) --> urls.py(找URL对应的试图函数) --> process_view中间件(如果有响应直接响应浏览器,没响应继续向后执行) --> views.py(执行url对应的试图函数,然后响应用户请求(如果views.py有异常就执行:procss_exception中间件)(如果试图函数返回的相应对象有render方法就执行:process_template_response中间件)) --> 服务端响应的结果经过:process_response中间件后将响应展示在用户浏览器上。

2.2、定义中间件示例

1、settings.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',
    'MyMiddleware.MD1',      #定义md1中间件
    'MyMiddleware.MD2',      #定义md2中间件
]

2、在manage.py同级目录创建一个MyMiddleware.py的中间件文件,内容如下:

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

#request(请求):URL白名单中间件
'''
request请求时:从settings.py里的MIDDLEWARE = []配置里从上往下执行
response请求时:从settings.py里的MIDDLEWARE = []配置里从下往上执行
'''
URL = ['/xx/','/index/','/oo/']       #定义URL白名单
class MD1(MiddlewareMixin):
    #request方法必须要有request参数
    def process_request(self,request):
        print("这是第一个中间件")
        if request.path_info in URL:
            return          #如果用户请求的URL在白名单里,就什么也不干,继续向后执行
        else:
            #否则就返回"gjbd!"
            return HttpResponse("gjbd!")

    #response方法必须要有request和response参数,(request里是请求的信息。response里是响应的信息)
    def process_response(self,requst,response):
        '''
        :param requst: 浏览器发来的请求
        :param response: 服务端的响应
        :return:
        '''
        print("这是MD1里的response中间件")
        return response       #如果这里没对response方法做修改就是将服务器端返回的原数据返回给用户

    #
    def process_view(self, request, view_func, view_args, view_kwargs):
        '''
        :param request:    浏览器发来的请求对象
        :param view_func:    将要执行的试图函数名字
        :param view_args:    将要执行的试图函数的位置参数
        :param view_kwargs:   将要执行的试图函数的关键字参数
        :return:
        '''
        print("这是MD1里面的view方法")          #process_view中间件是URL找到对应关系之后,执行view函数之前执行的

class MD2(MiddlewareMixin):

    def process_request(self,request):
        print("这是第二个中间件")

    def process_response(self,requst,response):
        print("这是md2里的response中间件")
        return response

三、附上基于中间件实现的登陆验证

1.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'),
]

2.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 == "zmr" 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")

3.login.html代码如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="x-ua-compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>登录页面</title>
</head>
<body>
<form action="/login/" method="post">
    <p>
        <label for="user">用户名:</label>
        <input type="text" name="user" id="user">
    </p>
    <p>
        <label for="pwd">密 码:</label>
        <input type="text" name="pwd" id="pwd">
    </p>
    <input type="submit" value="登录">
</form>
</body>
</html>

4.中间件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

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

5.在settings.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',
]

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

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

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

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

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

发表评论

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: