中间件:
中间件是介于request和response之间的一道处理过程,它在全局上改变了jdango的输入和输出,所以要谨慎使用。它在视图函数执行之前和执行之后做一些额外的操作,本质上是一个自定义类,且定义了几个方法。
django自带的中间件
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',
]
自定义中间件
中间件可以定义5个方法,其中主要是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,则直接返回该对象给用户,后面的方法什么的都不会执行。
用户发送请求后会依次经过所有中间件的process_request,然后到达view函数,view函数执行完后,process_response再次穿过中间件,然后返回给请求者。
process_request方法
process_request有一个参数,就是request, 这个request传到视图函数仍叫request,当返回None时,继续执行下一个中间件,如果返回的是HttpResponse对象,,是直接返回给浏览器。
from django.utils.deprecation import MiddlewareMixin
class MD1(MiddlewareMixin):
def process_request(self, request):
print("MD1里面的 process_request")
class MD2(MiddlewareMixin):
def process_request(self, request):
print("MD2里面的 process_request")
pass
注意:写好中间件后记得注册到setting中
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',
'middlewares.MD1',
'middlewares.MD2'
]
# 自定义中间件MD1,这个写的是你项目路径下的一个路径,例如,如果你放在项目下,文件夹名成为utils,那么这里应该写utils.middlewares.MD1
此时访问一个视图函数:会产生下面的结果 :
MD1里面的 process_request
MD2里面的 process_request
app01 中的 index视图
可以看到:
中间件的process_request方法在视图函数之前执行,
顺序按照MIDDLEWARE中注册顺序,从上到下执行。
不同中间件之间传递的对象是同一个对象
process_response
它有两个参数,一个request,一个response。response是视图函数返回的HttpResponse对象。process_response方法返回值必须是HttpResponse对象。
与上面的process_request相反,它是从下往上执行的,
执行流程:
process_view(self.request,view_func,view_args, view_kwargs)
request, HttpRequest对象
view_func django即将使用的视图函数(函数对象)
view_args 传给视图的位置参数列表
view_kwargs 传递给视图的关键字参数的字典
其中view_args, view_kwargs中都不包含request参数。
process_view会在调用视图函数前调用process_view方法。返回值是一个HttpResponse对象,
流程:
它是在process_request之后 ,视图函数之前执行的。如果其中一个process_view返回了HttpResponse对象,则执行顺序就会改成下面这样:
process_exception(self,request,exception)
request是一个HttpRequest对象
exception 是视图函数异常产生的Exception对象
此方法只有视图函数中出现异常才会执行,同样只要它返回了HttpResponse对象,后面的流程将被跳过不执行,直接返回给请求用户。
process_template_response(self, request,response)
request是HttpRequest对象,response是TemplateResponse对象(由视图函数或者中间件产生)
process_template_response是在视图函数执行冠希民后立即执行,但它有一个前提条件,那是视图函数返回的对象有一个render()方法,
应用:
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))
补充:Django生命周期:
django请求流程图:
中间件版的登陆验证:简单的演示下原理
from django.utils.deprecation import MiddlewareMixin
from django.shortcuts import reverse, redirect
class Own_Auth(MiddlewareMixin):
white_list = ['/login/', '/admin/', '/admin/login/', ]
def process_request(self, request):
next_url = request.path
is_login = request.session.get('is_login', None)
if is_login or next_url in self.white_list:
return None
else:
return redirect(reverse("account:login"))
注意:
中间件写好后要注册到settings的midddleware中。因为process_request会在每个views之前执行,所以一定要加入白名单,否则访问所有的url都会跳转到登陆页面。另外要防止形成递归。
只有返回None时,后面的流程都会继续执行。否则会在此截胡。