Django中间件 - django web程序的大门 | Python 主题月

1,212 阅读5分钟

本文正在参加「Python主题月」,详情查看 活动链接

微信公众号搜索【程序媛小庄】,Rest cannot be enjoyed by lazy people.

前言

Django请求生命周期的整个过程中,还有一个非常重要的部分 - django中间件,django中间件在整个请求过程中是一个类似于应用程序的门户的这样一个作用,请求要想到达django应用程序部分就不需要经过中间件,响应返回给请求方也要经过中间件。

django中间件的功能

事实上只要是涉及到项目全局的功能,中间件都可以实现,比如:

①全局身份校验

②全局访问频率校验

③全局权限校验

...

django中间件的代码规律

django自带了七个中间件,在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',
    
]

这七个中间件有什么规律呢?要研究中间件的规律就需要从源码入手,可是中间件的源码是列表存字符串,如何查看源码呢?其实这个字符串就表示导入的模块,使用了importlib模块就可以实现使用字符串导入模块,因此列表中的每一行都是在导入模块,比如django.middleware.security.SecurityMiddleware就等同于from django.middleware.security import SecurityMiddleware,如此就可以看见每一个Django中间件的源码了。下面是部分中间件的简略代码:

class SessionMiddleware(MiddlewareMixin):
    def process_request(self, request):
        session_key = request.COOKIES.get(settings.SESSION_COOKIE_NAME)
        request.session = self.SessionStore(session_key)
    def process_response(self, request, response):
        return response
      
class CsrfViewMiddleware(MiddlewareMixin):
  	def process_request(self, request):
        csrf_token = self._get_token(request)
        if csrf_token is not None:
            # Use same token next time.
            request.META['CSRF_COOKIE'] = csrf_token
    def process_view(self, request, callback, callback_args, callback_kwargs):
        return self._accept(request)

    def process_response(self, request, response):
        return response
      
class AuthenticationMiddleware(MiddlewareMixin):
    def process_request(self, request):
        request.user = SimpleLazyObject(lambda: get_user(request))
    
    def process_response(self, request, response):
        return response

有兴趣的小伙伴们可以打开看看所有中间件的源码可以发现,每个中间件都是一个类,都继承了MiddlewareMixin,并且每个类下面的方法都是process_xxx方法,并且每个中间件下面都有process_requestprocess_response方法,这两个方法是中间件中最重要的两个方法,除了这两个非常重要的方法之外还有其他三个方法process_viewprocess_template_responseprocess_exception,django提供了上述五个方法可以让我们自定义中间件,通过我们自己定义的中间件就可以发现django中间件的执行规律,所谓知彼知己,百战不殆

首先在项目根目录下创建一个中间件目录middleware,在该目录下创建中间件文件my_middeware.py文件。

# middleware/my_middleware.py

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


class MyMiddleWare1(MiddlewareMixin):

    def process_request(self, request):
        print('我是第一个中间件的process_request')

    def process_response(self, request, response):
        '''
        :param request:
        :param response: django后端返回给浏览器的内容
        :return:
        '''
        print('我是第一个中间件的process_response')
        # 将后端内容返回给浏览器客户端,不返回就相当于拦截了后端的内容,不给浏览器返回后端内容
        return response

    def process_view(self, request, callback, callback_args, callback_kwargs):
        print('view')

    def process_template_response(self, request, response):
        print('template')
        return response


class MyMiddle2(MiddlewareMixin):
    def process_request(self,request):
        print('我是第二个中间件的process_request')

    def process_response(self, request, response):
        print('我是第二个中间件的process_response')
        # 也可以返回其他内容给客户端
        return HttpResponse('就是不给你看后端数据')

定义好中间件之后不要忘记在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',
    # 自定义中间件
    'middleware.my_middleware.MyMiddle1',
    'middleware.my_middleware.MyMiddle2'
]

下面是视图函数中的代码:

# views.py

from django.shortcuts import render,HttpResponse

# Create your views here.
def index(request):
    obj = HttpResponse('index')
    def render():  # 中间件中的process_template_response方法需要render方法
        print('我执行了嘿')
        return HttpResponse('98k')
    obj.render = render
    return obj

我们启动django项目之后,访问127.0.0.1:8000/index之后在终端输出的内容如下:

我是第一个中间件的process_request
我是第二个中间件的process_request
我是第二个中间件的process_response
我是第一个中间件的process_response

客户端浏览器返回结果如下:

image-20210718115152659

通过后端返回给前端的结果和终端输出的内容可以总结一下中间件方法的执行规律

- process_request
	1.请求来的时候需要经过每一个中间件里面的process_request方法,结果的顺序是按照配置文件中注册的中间件从上往下的顺序依次执行
	2.如果中间件里面没有定义该方法,那么直接跳过执行下一个中间件
	3.如果该方法返回了HttpResponse对象,那么请求将不再继续往后执行,而是直接原路返回
	4.process_request方法就是用来做全局相关的所有限制功能
    
- process_response
	1.响应走的时候需要经过每一个中间件里面的process_response方法
	2.该方法有两个额外的参数request,response
	3.该方法必须返回一个HttpResponse对象
    	1.默认返回的就是形参response,
    	2.也可以自己返回自己的,但是返回自己的response对象就会拦截服务器端原本要返回给客户端的响应数据
		3.不返回的话浏览器客户端会报错:'NoneType' object has no attribute 'get'
	4.顺序是按照配置文件中注册了的中间件从下往上依次经过,如果没有定义的话 直接跳过执行下一个
    
- process_view
	路由匹配成功之后,执行视图函数之前,会自动执行中间件里面的该方法
	顺序是按照配置文件中注册的中间件从上往下的顺序依次执行
	
- process_template_response
	返回的HttpResponse对象有render属性的时候才会触发
	顺序是按照配置文件中注册了的中间件从下往上依次执行
	
- process_exception
	当视图函数中出现异常的情况下触发
	顺序是按照配置文件中注册了的中间件从下往上依次经过

可能会有小伙伴问,如果在第一个自定义中间件中的process_request方法中就返回了HttpResponse对象,那么返回响应的时候是经过所有的中间件里面的process_response还是有其他情况?如果在第一自定义中间件的process_request方法就已经返回了HttpResponse对象,这个中间件后面所有中间件的process_request process_response都不会执行了,就是原路返回。

结语

文章首发于微信公众号程序媛小庄,同步于掘金

码字不易,转载请说明出处,走过路过的小伙伴们伸出可爱的小指头点个赞再走吧(╹▽╹)

image.png