一、Django中间件的执行流程
1.1、Django中间件简介
Django的中间件类似于linux中的管道符,实质就是一个类,类之中有Django已经定义好了一些方法.
每个http请求都会执行中间件中的一个或多个方法:
1.进入Django中的请求都会执行process_request方法;
2.Django返回的信息都会执行process_response方法;
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',
]
导入 from django.middleware.csrf import CsrfViewMiddleware模块,查看其源码 class CsrfViewMiddleware(MiddlewareMixin)
可以看到 CsrfViewMiddleware 是继承 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
可以知道MiddlewareMixin是调用了其内部的call方法,call方法以反射的方式执行process_request和process_response方法。
1.2、中间件的应用
新建一个middleware项目,在项目的根目录中新建一个名为middleware的包,在这个package中,新建一个middleware.py文件。
from django.utils.deprecation import MiddlewareMixin
class middle_ware1(MiddlewareMixin):
def process_request(self,request):
print("middle_ware1.process_request")
def process_response(self,request,response):
print("middle_ware1.process_response")
return response
# 在settings.py配置文件的第一行注册这个中间件
MIDDLEWARE = [
'middleware.middleware.middle_ware1'
'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',
]
现在如果有http请求到达服务端,先执行中间件middle_ware1的process_request方法,再执行后面的中间件,然后到达视图函数。
定义一个视图函数index,配置好路由映射表
def index(request):
print("index page")
return HttpResponse("index")
启动程序,在浏览器中输入http://127.0.0.1:8000/index,会在服务端的后台打
middle_ware1.process_request
index page
middle_ware1.process_response
前端的页面为显示为:
index
通过这个我们知道,所有的请求都会经过middle_ware1这个中间件,先执行process_request方法,再执行视图函数本身;
最后执行process_response方法,Django会把process_response方法的返回值返回给客户端。
现在再加一个定义一个middle_ware2的中间件
from django.utils.deprecation import MiddlewareMixin
class middle_ware2(MiddlewareMixin):
def process_request(self,request):
print("middle_ware2.process_request")
def process_response(self,request,response):
print("middle_ware2.process_response")
return response
在settings.py配置文件中注册:
MIDDLEWARE = [
'middleware.middleware.middle_ware1',
'middleware.middleware.middle_ware2',
'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',
]
重启程序,再次刷新网页,服务端打印信息:
middle_ware1.process_request
middle_ware2.process_request
index page
middle_ware2.process_response
middle_ware1.process_response
中间件的依次执行为:
先执行middle_ware1的process_request方法;
再执行middle_ware2的类的process_request方法;
最后才执行Django的视图函数;
返回时,先执行middle_ware2的类中的;process_response函数;
然后再执行middle_ware1的类中的process_response函数。
上面的例子中,process_response方法设置了return值.假如process_response没有return值,会怎么样呢?
把middle_ware1中间件的process_response方法中的return注释掉,再次刷新网页,在浏览器的网页上显示报错信息,如下:
A server error occurred. Please contact the administrator;
http请求到达Django后,先经过自定义的中间件middle_ware1和middle_ware2,再经过Django内部定义的中间件到达视图函数;
视图函数执行完成后,一定会返回一个HttpResponse或者render。
通过查看render的源码可知,render方法本质上也是调用了HttpResponse
def render(request, template_name, context=None, content_type=None, status=None, using=None):
content = loader.render_to_string(template_name, context, request, using=using)
return HttpResponse(content, content_type, status)
户定义的中间件,最后返回给前端网页.
所以用户定义的中间件的process_response方法必须设定返回值,否则程序会报错.
同时,process_response方法中的形参response就是视图函数的返回值。
那么我们是否可以自己定义这个形参的返回值呢?
用户发过来的请求信息是固定的,因为所有的请求信息和返回信息都要经过中间件,中间件有可能会修改返回给用户的信息,所以有可能会出现用户收到的返回值与视图函数的返回值不一样的情况。
例如 返回给用户的信息包含响应头和响应体,但是开发者在视图函数中没有设置响应头,所以Django会在返回的信息中自动加上响应头;
前面process_response方法设置了返回值,process_request中没有设置返回值,如果为process_response设置一个返回值,结果会怎么样呢?
为中间件middle_ware1的process_request方法设置返回值
return HttpResponse("request message")刷新浏览器,服务端打印信息:
middle_ware1.process_request
middle_ware1.process_response
客户端浏览器显示信息为:
request message
先执行process_request方法,因为process_request方法有返回值,程序不会再执行后面的中间件,而是直接执行process_response方法,然后返回信息给用户.
在实际应用中,process_request方法不能直接设定返回值.如果必须在设定返回值,必须在返回值前加入条件判断语句。
常用在设定网站的黑名单的时候可以为process_request方法设置返回值。