一 中间件基本介绍
中间件顾名思义,是介于request与response处理之间的一道处理过程,相对比较轻量级,并且在全局上改变django的输入与输出。因为改变的是全局,所以需要谨慎实用,用不好会影响到性能。
Django的中间件的定义:
中间件是 Django 用来处理请求和响应的钩子框架。它是一个轻量级的、底层级的“插件”系统,用于全局性地控制Django 的输入或输出,可以理解为内置的app或者小框架。
如果想修改请求,例如被传送到view中的HttpRequest对象。 或者你想修改view返回的HttpResponse对象,这些都可以通过中间件来实现。
可能你还想在view执行之前做一些操作,这种情况就可以用 middleware来实现。
Django默认的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配置项是一个列表,列表中是一个个字符串,这些字符串其实是一个个类,也就是一个个中间件。cnfs也是一个中间件
二 自建一个中间件
2.1 process_request中间件
root@darren-virtual-machine:~/PycharmProjects/cookie_seesion# vim cookie/Middlewares.py
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 方法")
注册中间件
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', 'cookie.Middlewares.MD1', 'cookie.Middlewares.MD2', ]
访问http://127.0.0.1:8000/cookie/login/,调试结果如下
MD1下的process_request 方法
MD2下的process_request 方法
这里的结果是按照注册顺序执行的
配置views
from django.shortcuts import render,redirect,HttpResponse # Create your views here. def login_required(func): def inner(request,*args,**kwargs): if not request.COOKIES.get("is_login"): return redirect("/cookie/login/") rep = func(request,*args,**kwargs) return rep return inner @login_required def index(request): # if not request.COOKIES.get("is_login"): # return redirect("/cookie/login/") print("index 视图") return render(request,"index.html") def login(request): if request.method == "GET": return render(request,"login.html") else: username = request.POST.get("username") password = request.POST.get("password") if username == "joy" and password == "123456": rep = redirect("/cookie/index/") rep.set_cookie("is_login",True) return rep else: return redirect("/cookie/login/") def loginout(request): rep = redirect("/cookie/login/") rep.delete_cookie("is_login") return rep @login_required def order(request): # if not request.COOKIES.get("is_login"): # return redirect("/cookie/login/") return HttpResponse("oreder success")
登录查看结果
MD1下的process_request 方法
MD2下的process_request 方法
index 视图
process_request是在view之后输出的
2.2 process_reponse中间件
root@darren-virtual-machine:~/PycharmProjects/cookie_seesion# vim cookie/Middlewares.py
访问报错
这是因为在request,必须有回应
输出结果
MD1下的process_request 方法
MD2下的process_request 方法
MD2下的process_reponse 方法
MD1下的process_reponse 方法
先执行response的MD2
添加响应
结果
MD1下的process_request 方法
MD2下的process_request 方法
index 视图
MD2下的process_reponse 方法
MD1下的process_reponse 方法
在return response返回的对象就是
验证:
views文件
from django.shortcuts import render,redirect,HttpResponse # Create your views here. def login_required(func): def inner(request,*args,**kwargs): if not request.COOKIES.get("is_login"): return redirect("/cookie/login/") rep = func(request,*args,**kwargs) return rep return inner @login_required def index(request): # if not request.COOKIES.get("is_login"): # return redirect("/cookie/login/") print("index 视图") rep = render(request,"index.html") print(id(rep)) return rep def login(request): if request.method == "GET": return render(request,"login.html") else: username = request.POST.get("username") password = request.POST.get("password") if username == "joy" and password == "123456": rep = redirect("/cookie/index/") rep.set_cookie("is_login",True) return rep else: return redirect("/cookie/login/") def loginout(request): rep = redirect("/cookie/login/") rep.delete_cookie("is_login") return rep @login_required def order(request): # if not request.COOKIES.get("is_login"): # return redirect("/cookie/login/") return HttpResponse("oreder success")
中间件
root@darren-virtual-machine:~/PycharmProjects/cookie_seesion# vim cookie/Middlewares.py
from django.utils.deprecation import MiddlewareMixin class MD1(MiddlewareMixin): def process_request(self,request): print("MD1下的process_request 方法") def process_response(self,request,response): print("MD1下的process_reponse 方法") print(id(response)) return response class MD2(MiddlewareMixin): def process_request(self, request): print("MD2下的process_request 方法") def process_response(self,request,response): print("MD2下的process_reponse 方法") return response
访问结果,是一致的
MD1下的process_request 方法 MD2下的process_request 方法 index 视图 139857132829104 MD2下的process_reponse 方法 MD1下的process_reponse 方法 139857132829104
所以上面错误的原因,是因为resonse没有返回值,则默认的返回值为null,导致报错,返回response后,就是返回render(request,"index.html")
在request添加返回值
root@darren-virtual-machine:~/PycharmProjects/cookie_seesion# vim cookie/Middlewares.py
from django.utils.deprecation import MiddlewareMixin from django.shortcuts import render,redirect,HttpResponse class MD1(MiddlewareMixin): def process_request(self,request): print("MD1下的process_request 方法") return HttpResponse("Hello 我来了") def process_response(self,request,response): print("MD1下的process_response 方法") print(id(response)) return response class MD2(MiddlewareMixin): def process_request(self, request): print("MD2下的process_request 方法") def process_response(self,request,response): print("MD2下的process_response 方法") return response
访问http://127.0.0.1:8000/cookie/login/,没有到view层
输出
MD1下的process_request 方法
MD1下的process_response 方法
140023033668160
如图,当reques的中间件中,有返回值,就会直接返回,不会走到下面的reques和视图层,生命请求周期如下:
2.3 process_view方法
该方法有四个参数
- request是HttpRequest对象。
- view_func是Django即将使用的视图函数。 (它是实际的函数对象,而不是函数的名称作为字符串。)
- view_args是将传递给视图的位置参数的列表.
- view_kwargs是将传递给视图的关键字参数的字典。 view_args和view_kwargs都不包含第一个视图参数(request)。
Django会在调用视图函数之前调用process_view方法。
它应该返回None或一个HttpResponse对象。 如果返回None,Django将继续处理这个请求,执行任何其他中间件的process_view方法,然后在执行相应的视图。 如果它返回一个HttpResponse对象,Django不会调用适当的视图函数。 它将执行中间件的process_response方法并将应用到该HttpResponse并返回结果。
添加process_view
root@darren-virtual-machine:~/PycharmProjects/cookie_seesion# vim cookie/Middlewares.py
from django.utils.deprecation import MiddlewareMixin from django.shortcuts import render,redirect,HttpResponse class MD1(MiddlewareMixin): def process_request(self,request): print("MD1下的process_request 方法") #return HttpResponse("Hello 我来了") def process_response(self,request,response): print("MD1下的process_response 方法") #print(id(response)) return response def process_view(self,request,view_func,view_args,view_kwargs): print("MD1下的process_view 方法") class MD2(MiddlewareMixin): def process_request(self, request): print("MD2下的process_request 方法") def process_response(self,request,response): print("MD2下的process_response 方法") return response def process_view(self,request,view_func,view_args,view_kwargs): print("MD2下的process_view 方法")
输出结果
MD1下的process_request 方法
MD2下的process_request 方法
MD1下的process_view 方法
MD2下的process_view 方法
index 视图
MD2下的process_response 方法
MD1下的process_response 方法
process_view方法是在process_request之后,视图函数之前执行的,执行顺序按照MIDDLEWARE中的注册顺序从前到后顺序执行。
在MD1下的porcess_view返回一个返回值
from django.utils.deprecation import MiddlewareMixin from django.shortcuts import render,redirect,HttpResponse class MD1(MiddlewareMixin): def process_request(self,request): print("MD1下的process_request 方法") #return HttpResponse("Hello 我来了") def process_response(self,request,response): print("MD1下的process_response 方法") #print(id(response)) return response def process_view(self,request,view_func,view_args,view_kwargs): print("MD1下的process_view 方法") return view_func(request) class MD2(MiddlewareMixin): def process_request(self, request): print("MD2下的process_request 方法") def process_response(self,request,response): print("MD2下的process_response 方法") return response def process_view(self,request,view_func,view_args,view_kwargs): print("MD2下的process_view 方法")
执行结果
MD1下的process_request 方法
MD2下的process_request 方法
MD1下的process_view 方法
index 视图
MD2下的process_response 方法
MD1下的process_response 方法
2.4 process_exception
语法:
process_exception(self, request, exception)
该方法两个参数:
- HttpRequest对象
- exception是视图函数异常产生的Exception对象。
这个方法只有在视图函数中出现异常了才执行,它返回的值可以是一个None也可以是一个HttpResponse对象。如果是HttpResponse对象,Django将调用模板和中间件中的process_response方法,并返回给浏览器,否则将默认处理异常。如果返回一个None,则交给下一个中间件的process_exception方法来处理异常。它的执行顺序也是按照中间件注册顺序的倒序执行。
添加process_exception
from django.utils.deprecation import MiddlewareMixin from django.shortcuts import render,redirect,HttpResponse class MD1(MiddlewareMixin): def process_request(self,request): print("MD1下的process_request 方法") #return HttpResponse("Hello 我来了") def process_response(self,request,response): print("MD1下的process_response 方法") #print(id(response)) return response def process_view(self,request,view_func,view_args,view_kwargs): print("MD1下的process_view 方法") #return view_func(request) def process_exception(self,request,exception): print("MD1下的process_exception 方法") class MD2(MiddlewareMixin): def process_request(self, request): print("MD2下的process_request 方法") def process_response(self,request,response): print("MD2下的process_response 方法") return response def process_view(self,request,view_func,view_args,view_kwargs): print("MD2下的process_view 方法") def process_expection(self,request,exception): print("MD2下的process_exception 方法")
访问结果
MD1下的process_request 方法
MD2下的process_request 方法
MD1下的process_view 方法
MD2下的process_view 方法
index 视图
MD2下的process_response 方法
MD1下的process_response 方法
并没有exception,是因为需要view异常才会触发
制造views异常
from django.shortcuts import render,redirect,HttpResponse # Create your views here. def login_required(func): def inner(request,*args,**kwargs): if not request.COOKIES.get("is_login"): return redirect("/cookie/login/") rep = func(request,*args,**kwargs) return rep return inner @login_required def index(request): # if not request.COOKIES.get("is_login"): # return redirect("/cookie/login/") print("index 视图") int("aaa") rep = render(request,"index.html") #print(id(rep)) return rep def login(request): if request.method == "GET": return render(request,"login.html") else: username = request.POST.get("username") password = request.POST.get("password") if username == "joy" and password == "123456": rep = redirect("/cookie/index/") rep.set_cookie("is_login",True) return rep else: return redirect("/cookie/login/") def loginout(request): rep = redirect("/cookie/login/") rep.delete_cookie("is_login") return rep @login_required def order(request): # if not request.COOKIES.get("is_login"): # return redirect("/cookie/login/") return HttpResponse("oreder success")
访问http://127.0.0.1:8000/cookie/index/
输出结果
MD1下的process_request 方法
MD2下的process_request 方法
MD1下的process_view 方法
MD2下的process_view 方法
index 视图
MD2下的process_exception 方法
MD1下的process_exception 方法
MD2下的process_response 方法
MD1下的process_response 方法
在exception添加错误返回
from django.utils.deprecation import MiddlewareMixin from django.shortcuts import render,redirect,HttpResponse class MD1(MiddlewareMixin): def process_request(self,request): print("MD1下的process_request 方法") #return HttpResponse("Hello 我来了") def process_response(self,request,response): print("MD1下的process_response 方法") #print(id(response)) return response def process_view(self,request,view_func,view_args,view_kwargs): print("MD1下的process_view 方法") #return view_func(request) def process_exception(self,request,exception): print("MD1下的process_exception 方法") return HttpResponse(exception) class MD2(MiddlewareMixin): def process_request(self, request): print("MD2下的process_request 方法") def process_response(self,request,response): print("MD2下的process_response 方法") return response def process_view(self,request,view_func,view_args,view_kwargs): print("MD2下的process_view 方法") def process_exception(self,request,exception): print("MD2下的process_exception 方法")
访问结果没有报错
输出
MD1下的process_request 方法
MD2下的process_request 方法
MD1下的process_view 方法
MD2下的process_view 方法
index 视图
MD2下的process_exception 方法
MD1下的process_exception 方法
MD2下的process_response 方法
MD1下的process_response 方法
在MD2返回
from django.utils.deprecation import MiddlewareMixin from django.shortcuts import render,redirect,HttpResponse class MD1(MiddlewareMixin): def process_request(self,request): print("MD1下的process_request 方法") #return HttpResponse("Hello 我来了") def process_response(self,request,response): print("MD1下的process_response 方法") #print(id(response)) return response def process_view(self,request,view_func,view_args,view_kwargs): print("MD1下的process_view 方法") #return view_func(request) def process_exception(self,request,exception): print("MD1下的process_exception 方法") class MD2(MiddlewareMixin): def process_request(self, request): print("MD2下的process_request 方法") def process_response(self,request,response): print("MD2下的process_response 方法") return response def process_view(self,request,view_func,view_args,view_kwargs): print("MD2下的process_view 方法") def process_exception(self,request,exception): print("MD2下的process_exception 方法") return HttpResponse(exception)
访问结果
MD1下的process_request 方法
MD2下的process_request 方法
MD1下的process_view 方法
MD2下的process_view 方法
index 视图
MD2下的process_exception 方法
MD2下的process_response 方法
MD1下的process_response 方法
没有MD1的exception,已经跳过,流程如下
绿色为正常流程,红色是则MD2添加return返回