Django中的中间件(含Django完整生命周期图)
Django中间件简介
中间件顾名思义,是介于request与response处理之间的一道处理过程,相对比较轻量级,并且在全局上改变django的输入与输出。因为改变的是全局,所以需要谨慎实用,用不好会影响到性能
django 中的中间件(middleware),在django中,中间件其实就是一个类,在请求到来和结束后,django会根据自己的规则在合适的时机执行中间件中相应的方法
在django项目的settings模块中,有一个 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', ]
Django请求的一个生命周期
可以看出当一个请求来时,会依次执行每一个中间件中的process_request函数,再通过路由找到对应的视图函数执行,求情完成后,会再一次经过每一个中间件的process_response函数,再返回给浏览器
因此我们如果有一些操作是需要在执行每个views视图函数之前就要执行的可以添加中间件进行执行(如登录验证)
中间件与装饰器的选择
以后想要对所有的请求做统一操作时,用中间件
只是对少量的视图函数做操作时,用装饰器
中间件的写法
首先在项目内任意创建一个目录,在目录下创建一个py文件,名字随意
在该py文件中写中间件的类,这个类需要继承MiddlewareMixin(在1.7或1.8等老版本django中只需要继承object类即可)
from django.utils.deprecation import MiddlewareMixin from django.shortcuts import HttpResponse,redirect class AuthMiddleware(MiddlewareMixin): def process_request(self,request): # 如果么有返回值;返回None,表示可以继续往下执行 # 如果有返回值,执行自己的response以及以上的response。 if request.path_info == '/login/': return None user_info = request.session.get('user_info') if not user_info: # return HttpResponse('请登录') return redirect('/login/') def process_response(self,request,response): return response
在settings中配置
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.middleware.auth.AuthMiddleware', # 中间件的路径 ]
process_request和process_response的参数
process_request参数
self,request
def process_request(self,request): # 如果么有返回值;返回None,表示可以继续往下执行 # 如果有返回值,执行自己的response以及以上的response。 if request.path_info == '/login/': return None user_info = request.session.get('user_info') if not user_info: # return HttpResponse('请登录') return redirect('/login/')
process_response参数
self,request,response
def process_response(self,request,response): return response
process_request和process_response的返回值
process_request返回值
当process_request函数没有返回值(默认为None)或者返回None时,请求会接着往后走,执行后面的中间件直到视图函数
当process_request函数有返回值时,请求将不会再往后走,而是直接执行该中间件的process_response函数,并接着执行前面中间的process_response函数,直至返回给浏览器
process_response返回值
必须有返回值,否则会报错,返回response
process_view
定义如下的中间件
from django.utils.deprecation import MiddlewareMixin from django.shortcuts import HttpResponse class Md1(MiddlewareMixin): def process_request(self,request): print("Md1请求") #return HttpResponse("Md1中断") def process_response(self,request,response): print("Md1返回") return response def process_view(self, request, callback, callback_args, callback_kwargs): print("Md1view") class Md2(MiddlewareMixin): def process_request(self,request): print("Md2请求") return HttpResponse("Md2中断") def process_response(self,request,response): print("Md2返回") return response def process_view(self, request, callback, callback_args, callback_kwargs): print("Md2view")
在settings中配置
后端视图函数为
def index(request): print("view函数...") return HttpResponse("OK")
此时我们发送访问请求,服务器运行的结果为
Md1请求
Md2请求
Md1view
Md2view
view函数...
Md2返回
Md1返回
下图进行分析上面的过程:
当最后一个中间的process_request到达路由关系映射之后(这里要注意,如果能匹配到关系映射,则返回执行process_view,匹配不到则不会去执行process_view),返回到中间件1的process_view,然后依次往下,到达views函数,最后通过process_response依次返回到达用户
process_view可以用来调用视图函数:
class Md1(MiddlewareMixin): def process_request(self,request): print("Md1请求") #return HttpResponse("Md1中断") def process_response(self,request,response): print("Md1返回") return response def process_view(self, request, callback, callback_args, callback_kwargs): # return HttpResponse("hello") response=callback(request,*callback_args,**callback_kwargs) return response
结果如下:
Md1请求
Md2请求
view函数...
Md2返回
Md1返回
可以看到process_view的callback参数其实就是匹配到的views视图函数,而callback_args, callback_kwargs则是可能会有的参数
注意:process_view如果有返回值,会越过其他的process_view以及视图函数,但是所有的process_response都还会执行
process_exception
当执行出现出错时才会执行process_exception
修改中间件为
class Md1(MiddlewareMixin): def process_request(self,request): print("Md1请求") #return HttpResponse("Md1中断") def process_response(self,request,response): print("Md1返回") return response def process_view(self, request, callback, callback_args, callback_kwargs): # return HttpResponse("hello") # response=callback(request,*callback_args,**callback_kwargs) # return response print("md1 process_view...") def process_exception(self): print("md1 process_exception...") class Md2(MiddlewareMixin): def process_request(self,request): print("Md2请求") # return HttpResponse("Md2中断") def process_response(self,request,response): print("Md2返回") return response def process_view(self, request, callback, callback_args, callback_kwargs): print("md2 process_view...") def process_exception(self): print("md1 process_exception...")
结果如下:
Md1请求
Md2请求
md1 process_view...
md2 process_view...
view函数...
Md2返回
Md1返回
由于没有出错,所以process_exception并未执行
流程图如下:
当views出现错误时:
将md2的process_exception修改如下:
def process_exception(self,request,exception): print("md2 process_exception...") return HttpResponse("error")
并且在执行时发生错误
可以看到结果如下
Md1请求
Md2请求
md1 process_view...
md2 process_view...
view函数...
md2 process_exception...
Md2返回
Md1返回
出错后会从后往前执行每一个中间件的process_exception,当遇到有返回值的process_exception,前面的中间件的process_exception将不会执行,而是会直接去执行每个中间件的process_response