中间件
针对于登入验证的操作,我们可以通过最原始的在视图函数取得前端发过的登入数据,做相应的判断操作,进行相应的操作。或者通过ajax登入,后端发送状态验证,ajax拿到状态验证做相应的前端处理。
上面的这个方法,由于http的无状态特征,会出现以下几个弊端:1. 重复登入;2. 如果很多页面需要身份验证,都在视图里面写登入判断逻辑,代码太繁琐、冗余。
所以出现了cookie和session。cookie相当于一个'小甜点',一开始为空,一旦通过一次登入验证,后端便往它里面填东西(响应头里面),它保存在浏览器本地,当以后浏览器在向后端发送请求时会带着这个'甜点'(请求头里面),后端通过处理这个'小甜点',来验证是否通过验证。
session的出现,是由于cookie里面好多信息是保存在客户端本地,不安全。于是只给cookie添加一把'钥匙'数据(session_id),具体的数据是加密保存在服务端的数据库中。后端在接收到前端的请求后,通过请求头cookie里面的'钥匙',从自己本地数据库里面拿想要的数据,来进行身份验证。
但是,上面的这些方法,都要写一些验证的逻辑代码,或者装饰器,还是有些繁琐。这样中间件应运而生,身份验证过程在中间件中便可以完成。并且每个请求都要从中间里面走一遍,即都要身份一下。所以代码量减少了,只要一个身份验证的中间件即可。
具体的,从浏览器发送请求到客户端,到最后的浏览器渲染html文件的全过程,如下所示。浏览器发过的请求,经过wsgi.py(里面封装了socket,根据http协议,进行最基层的数据包解析)处理,第二步就要在中间件中走一遍。(注意是所有请求,包括静态文件请求都要经过中间件)
下图是Django默认的中间件,我们自己可以写中间件,做相应的逻辑处理。
class MD1(MiddlewareMixin):
#request这个参数必须有
def process_request(self, request):
print('MD1请求来了')
#request、response这两个参数必须有
def process_response(self, request, response):
print('MD1响应来了')
#必须有返回值,必然这个中间件上面的其余中间件就得不到response,会报错
return response
#return HttpResponse('ok')
中间件可以定义五个方法,其中process_request和process_response比较常用,这些方法的返回值可以是None(即不return)或一个HttpResponse对象,如果是None,则继续按照django定义的规则向后继续执行,如果是HttpResponse对象,则直接将该对象返回给用户。
- 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)
利用中间进行身份验证
class MD2(MiddlewareMixin):
# 判断访问的URL是否在白名单中
def process_request(self, request):
if request.path in whilename:
return None
else:
# is_login = request.session['is_login']
# 以上这种取值方法不好,因为在数据库中没有‘iis_login'(或为空)的情况下,会报错
# get方法在数据为空时,不会报错
is_login = request.session.get('is_login')
if is_login:
return None
else:
return redirect('mylogin')
def process_response(self, request, response):
print('MD2响应来了')
return response
process_view方法
Peocess_view方法中,含有4个参数。分别别:
1、request是HttpRequest对象。
2、view_func是Django即将使用的视图函数。 (它是的函数对象,加上括号可以直接执行)
3、view_args是将传递给视图的位置参数的列表.
4、view_kwargs是将传递给视图的关键字参数的字典。
- view_args和view_kwargs都不包含第一个视图参数(request)
Django在调用视图函数之前调用process_view方法。它可以返回None或一个HttpResponse对象。 如果返回None,Django将继续处理这个请求,再执行任何其他中间件的process_view方法,然后在执行相应的视图。 如果它返回一个HttpResponse对象,Django不会调用对应的视图函数。 它将执行中间件的process_response方法并将应用到该HttpResponse并返回结果。如下例子:
def process_view(self, request, view_func, view_args, view_kwargs):
print('MD1中的process_view')
print(view_func, view_func.__name__)
'''
提前执行视图函数,不用到了上图的试图函数的位置再执行,如果你视图函数有参数的话,可以这么写 view_func(request,view_args,view_kwargs)
'''
return view_func(request)
process_exception
process_exception(self, request, exception)
两个参数: HttpRequest对象、视图函数异常产生的Exception对象。
这个方法只有在视图函数中出现异常了才执行,它返回的值可以是一个None也可以是一个HttpResponse对象。如果是HttpResponse对象,Django将调用模板和中间件中的process_response方法,并返回给浏览器,否则将默认处理异常。如果返回一个None,则交给下一个中间件的process_exception方法来处理异常。它的执行顺序也是按照中间件注册顺序的倒序执行。
process_template_response(用的比较少)
process_template_response(self, request, response)
它的参数,一个HttpRequest对象,response是TemplateResponse对象(由视图函数或者中间件产生)。
process_template_response是在视图函数执行完成后立即执行,但是它有一个前提条件,那就是视图函数返回的对象有一个render()方法(或者表明该对象是一个TemplateResponse对象或等价方法)。