中间件
中间件 middleware
中间件的五个方法
中间件可以定义五个方法,分别是:(主要的是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)
定义
中间件顾名思义,是介于request与response处理之间的一道处理过程,相对比较轻量级,并且在全局上改变django的输入与输出。因为改变的是全局,所以需要谨慎实用,用不好会影响到性能。
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', ] 配置的是一个个路径,封装一些功能,相当于 from django.middleware.security import securitymiddleware
登录验证
条件:只有登录成功才能访问各个页面,也就是无论点击哪里都跳转到登录界面
用session时会报一个错误
low版本 装饰器版
views.py
from django.shortcuts import render,httpresponse,redirect # create your views here. def wrapper(f): def inner(request,*args,**kwargs): status = request.session.get("is_login") # 获取session的值, if status: return f(request,*args,**kwargs) else: return redirect("login") return inner @wrapper def home(request): return render(request,"home.html") def login(request): if request.method == "get": return render(request,"login.html") else: user = request.post.get("username") pwd = request.post.get("password") if user == "alex" and pwd == "123": request.session["is_login"] = true return redirect("home") else: return redirect("login") @wrapper def index(request): return render(request,"index.html")
高级版
1.设置自定义中间件
在应用app01中
在应用app01中创建一个包,随便起名字,一般都放在一个叫做utils的包里面,表示一个公用的组件,创建一个py文件,随便起名字,例如叫做:middlewares.py,内容如下
from django.utils.deprecation import middlewaremixin class loginauth(middlewaremixin): #请求来了,自动执行 def process_request(self,request): print("请求来了")
然后去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', 'app01.utils.mymiddleware.loginauth' ]
django的请求生命周期
具体解释
浏览器请求,wsgi.py,它封装这socket,request对象,request对象给中间键,中间件根据middleware封装的中间件一层一层向下执行,自动执行每个中间件中的请求函数
执行顺序从上到下,例如,我们把自定义的中间件放在session中间件的上边,那么session就不起作用了,所以自定义的中间件是放在最下边位置
-
中间件加工完之后,给了url控制器,然后执行视图函数views,视图函数再通过orm与数据库进行交互,并且渲染页面
注意如果此处没有return值,默认返回的是none,表示正常,向下执行,如果return值是别的值,那么就不会向下执行了,直接执行响应中间件的response方法给浏览器了
执行完成后,页面需要间数据返还给浏览器,不需要经过url,但是还会经过中间件
中间件中执行process_response方法
所以由上引入白名单概念,就是让不需要session的函数先执行,例如login函数
白名单
中间件的py文件中
from django.utils.deprecation import middlewaremixin from django.shortcuts import render,httpresponse,redirect class loginauth(middlewaremixin): #白名单 white_list = ["/login/",] def process_request(self,request): print("请求来了") path = request.path #获取请求路径 if path not in self.white_list: status = request.session.get("is_login") if not status: return redirect("login") def process_response(self,request,response): print("响应走了") return response
views.py 应用了中间件就不用了装饰器了
from django.shortcuts import render,httpresponse,redirect # create your views here. def home(request): print("这是home函数") return render(request,"home.html") def login(request): if request.method == "get": print("这是login函数") return render(request,"login.html") else: user = request.post.get("username") pwd = request.post.get("password") if user == "alex" and pwd == "123": request.session["is_login"] = true return redirect("home") else: return redirect("login") def index(request): print("这是index函数") return render(request,"index.html")
在上述代码中,请求白名单中的数据时,根据请求路径判断下列条件的结果,当路径在白名单中的时候,if条件不成立,默认返回none,正常执行views函数,如果访问home函数等,以为没有在白名单中,执行if条件,如果已经有了session值,则默认返回none,正常执行函数,如果没有session,则执行下一个if判断,重定向到login路径,再次请求,执行同上
中间件有多个方法时的执行顺序
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.utils.mymiddleware.loginauth' 'app01.utils.mymiddleware.md1', # 新增中间件 "app01.utils.mymiddleware.md2", # 新增中加件 ]
views.py
from django.shortcuts import render,httpresponse,redirect # create your views here. def home(request): print("这是home函数") return render(request,"home.html") def login(request): if request.method == "get": print("这是login函数") return render(request,"login.html") else: user = request.post.get("username") pwd = request.post.get("password") if user == "alex" and pwd == "123": request.session["is_login"] = true return redirect("home") else: return redirect("login") def index(request): print("这是index函数") return render(request,"index.html")
process_resquest 和 process_response 方法顺序
middleware.py 中间件中文件
class md1(middlewaremixin): def process_request(self,request): #request是一个请求的对象 print("md1的process_request方法",request) #return httpresponse("ok") ---------------------- 第一知识点 第一执行 def process_response(self,request,response): print("md1的process_response方法",response) return response #return httpresponse("ok") ---------------------- 第二知识点 第四执行 class md2(middlewaremixin): def process_request(self,request): print("md2的process_request方法",request) #return httpresponse("ok") ----------------------- 第三知识点 第二执行 def process_response(self,request,response): print("md2的process_response方法",response) #response 接收的是函数的返回值,是一个response对象 return response #return httpresponse("ok") ---------------------- 第四知识点 第三执行
有return自定义内容的时候
都是get方法时验证
第一知识点解释
md1的process_request方法 <wsgirequest: get '/index/'> md1的process_response方法 <httpresponse status_code=200, "text/html; charset=utf-8"> 当我们在浏览器发送请求时,执行到中间件时就不再向后执行,只执行返回函数process_response
第二知识点解释
md1的process_request方法 <wsgirequest: get '/index/'> md2的process_request方法 <wsgirequest: get '/index/'> 这是index函数 md2的process_response方法 <httpresponse status_code=200, "text/html; charset=utf-8"> md1的process_response方法 <httpresponse status_code=200, "text/html; charset=utf-8"> 当我们在浏览器发送请求时,由于返回值的位置是最后执行的,所以所有的函数都执行了,但是由于返回的是自定义的,而不是response对象,所以返回页面不是html文件,而是ok
第三知识点解释
md1的process_request方法 <wsgirequest: get '/login/'> md2的process_request方法 <wsgirequest: get '/login/'> md2的process_response方法 <httpresponse status_code=200, "text/html; charset=utf-8"> md1的process_response方法 <httpresponse status_code=200, "text/html; charset=utf-8"> 当我们在浏览器发送请求时,执行到中间件时就不再向后执行,只执行返回函数process_response,依次向上执行(中间件顺序) 所以返回页面不是html文件,而是ok
第四知识点解释
md1的process_request方法 <wsgirequest: get '/login/'> md2的process_request方法 <wsgirequest: get '/login/'> 这是login函数 md2的process_response方法 <httpresponse status_code=200, "text/html; charset=utf-8"> md1的process_response方法 <httpresponse status_code=200, "text/html; charset=utf-8"> 当我们在浏览器发送请求时,由于返回值的位置是最后执行的,所以所有的函数都执行了,但是由于返回的是自定义的,而不是response对象,所以返回页面不是html文件,而是ok
process_view
middleware.py
class md1(middlewaremixin): def process_request(self,request): #request是一个请求的对象 print("md1的process_request方法",request) # return httpresponse("ok") def process_response(self,request,response): print("md1的process_response方法",response) return response # return httpresponse("ok") def process_view(self,request,view_func,view_args,view_kwargs): print(view_func) print("md1的process_view") class md2(middlewaremixin): def process_request(self,request): print("md2的process_request方法",request) # return httpresponse("ok") def process_response(self,request,response): print("md2的process_response方法",response) #response 接收的是函数的返回值,是一个response对象 return response # return httpresponse("ok") def process_view(self,request,view_func,view_args,view_kwargs): print(view_func) print("md2的process_view")
index请求结果
md1的process_request方法 <wsgirequest: get '/login/'> md2的process_request方法 <wsgirequest: get '/login/'> <function login at 0x0000002b48eda2f0> md1的process_view <function login at 0x0000002b48eda2f0> md2的process_view 这是login函数 md2的process_response方法 <httpresponse status_code=200, "text/html; charset=utf-8"> md1的process_response方法 <httpresponse status_code=200, "text/html; charset=utf-8">
执行顺序图
process_exception
这个比较特殊,只有在有报错的情况下才执行,否则不执行
middleware.py
class md1(middlewaremixin): def process_request(self,request): #request是一个请求的对象 print("md1的process_request方法",request) # return httpresponse("ok") def process_response(self,request,response): print("md1的process_response方法",response) return response # return httpresponse("ok") def process_view(self,request,view_func,view_args,view_kwargs): print(view_func) print("md1的process_view") def process_exception(self, request, exception): print(exception) print("md1的process_exception") class md2(middlewaremixin): def process_request(self,request): print("md2的process_request方法",request) # return httpresponse("ok") def process_response(self,request,response): print("md2的process_response方法",response) #response 接收的是函数的返回值,是一个response对象 return response # return httpresponse("ok") def process_view(self,request,view_func,view_args,view_kwargs): print(view_func) print("md2的process_view") def process_exception(self, request, exception): print(exception) #打印的是抛出的错误信息 print("md2的process_exception")
为了报错修改views.py代码
def home(request): print("这是home函数") return render(request,"home.html") def login(request): if request.method == "get": print("这是login函数") raise valueerror("抛出错误") #------注意此处要抛错才能执行exception return render(request,"login.html") else: user = request.post.get("username") pwd = request.post.get("password") if user == "alex" and pwd == "123": request.session["is_login"] = true return redirect("home") else: return redirect("login") def index(request): print("这是index函数") return render(request,"index.html")
执行结果
md1的process_request方法 <wsgirequest: get '/login/'> md2的process_request方法 <wsgirequest: get '/login/'> <function login at 0x0000000ad8f5a268> md1的process_view <function login at 0x0000000ad8f5a268> md2的process_view 这是login函数 抛出错误 md2的process_exception 抛出错误 md1的process_exception internal server error: /login/ traceback (most recent call last): file "c:\python36\lib\site-packages\django\core\handlers\exception.py", line 41, in inner response = get_response(request) file "c:\python36\lib\site-packages\django\core\handlers\base.py", line 187, in _get_response response = self.process_exception_by_middleware(e, request) file "c:\python36\lib\site-packages\django\core\handlers\base.py", line 185, in _get_response response = wrapped_callback(request, *callback_args, **callback_kwargs) file "d:\django项目\day67\zhongjianjian\app01\views.py", line 23, in login raise valueerror("抛出错误") valueerror: 抛出错误 [16/oct/2019 17:25:55] "get /login/ http/1.1" 500 65127 md2的process_response方法 <httpresponse status_code=500, "text/html"> md1的process_response方法 <httpresponse status_code=500, "text/html">