文章目录
- 一、什么是中间件
- 二、中间件有什么用
- 三、Django自定义中间件
- 中间件中主要方法及作用
- `创建自定义中间件的步骤:`
- process_request与process_response方法
- process_view方法
- process_exception
- process_template_response(不常用)
- 四、CSRF_TOKEN
流程图介绍中间件
一、什么是中间件
Django中间件类似于django的门户,所有的请求来和响应走走必须经过中间件
中间件顾名思义,是介于request与response处理之间的一道处理过程
,相对比较轻量级,并且在全局上改变django的输入与输出。因为改变的是全局,所以需要谨慎实用,用不好会影响到性能
Django官方中间件的定义:
Middleware is a framework of hooks into Django’s request/response processing.
It’s a light, low-level “plugin” system for globally altering Django’s input or output.
中间件它的执行位置在web服务网关接口之后,在路由匹配之前执行的
二、中间件有什么用
如果你想修改请求,例如被传送到view中的HttpRequest
对象。 或者你想修改view返回的HttpResponse
对象,这些都可以通过中间件来实现。
可能你还想在view执行之前做一些操作,这种情况就可以用 middleware来实现。
Django默认的中间件:(在django项目的settings模块中,有一个 MIDDLEWARE_CLASSES 变量,其中每一个元素就是一个中间件,如下)
'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',
]
1.django.middleware.security.SecurityMiddleware
做了一些安全处理的中间件。比如设置XSS防御的请求头,比如做了http协议转为https协议的工作等。
2.django.contrib.sessions.middleware.SessionMiddleware
session中间件。会给request添加一个处理好的session对象。
3.django.middleware.common.CommonMiddleware
通用中间件,会处理一些URL,比如baidu.com会自动的处理成www.baidu.com。
4.django.middleware.csrf.CsrfViewMiddleware
保护中间件,在提交表单的时候必须加入csrf_token,cookie中也会生成一个名叫csrftoken的值,也会在header中加入一个HTTP_X_CSRFTOKEN的值来放置CSRF攻击。SessionMiddleware必须出现在CsrfMiddleware之前。
5.django.contrib.auth.middleware.AuthenticationMiddleware
用户授权中间件。会给reqeust添加一个user对象的中间件。该中间件必须在sessionmiddleware后面。
6.django.contrib.messages.middleware.MessageMiddleware
消息处理中间件。为了在多个模版中可以使用我们返回给模版的变量,并且简化操作。
7.django.middleware.clickjacking.XFrameOptionsMiddleware
防止通过浏览器页面跨Frame出现clickjacking(欺骗点击)攻击出现。
中间件的执行顺序
每一个中间件在请求来的时候或者响应的时候都具有一定的作用。
三、Django自定义中间件
Django给我们提供了创建自定义中间件的方式,通过创建自定义中间件来实现全局的功能,例如
全局用户黑名单校验、全局用户访问频率校验、网站全局用户身份校验等等。
中间件中主要方法及作用
'中间件类必须继承自django.utils.deprecation.MiddlewareMixin类'
process_request(self,request)
用途:过滤请求
'''
1.请求来的时候会按照配置文件中注册了的中间件,从上往下依次执行每一个中间件里面的porcess_request方法,如果没有则直接跳过
2.该方法如果返回了HttpResponse对象,那么请求不会再往后执行,原路返回
'''
process_view(self, request, callback, callback_args, callback_kwargs)
用途:用于代码层面的替换和过滤,这个方法可以拿到视图函数的参数
'''当路由匹配成功之后,执行视图函数之前,自动触发'''
process_template_response(self,request,response)
'''当视图函数返回的数据对象中含有render属性对应render函数才会触发'''
process_exception(self, request, exception)
用途:用于一般用于捕获发生的异常,并将其邮件发送给开发人员
'''当视图函数报错之后,自动触发'''
process_response(self, request, response)
'''
1.响应走的时候会按照配置文件中注册了的中间件,从下往上依次执行每一个中间件里面的process_response方法,如果没有则直接跳过
2.该方法有两个形参request和response,并且默认情况下应该返回response
3.该方法也可以自己返回HttpResponse对象,相当于狸猫换太子
'''
'如果请求的过程中process_request方法直接返回了HttpResponse对象那么会原地执行同级别process_response返回后直接返回(flask则不同)'
创建自定义中间件的步骤:
1.在项目名下或者任意的应用名下创建一个文件夹
2.在该文件夹内创建一个任意名称的py文件
3.在该py文件中编写一个自定义的中间件类,并且必须继承MiddlewareMixin
4.紧接着去settings配置文件中注册中间件
process_request与process_response方法
当用户发起请求的时候会依次执行经过的所有中间件,这个时候的请求首先进入process_request
,最后到达views的函数中,views函数处理后,在依次穿过中间件,这个时候是process_response
,最后返回给请求者。
我们要自己定义中间件的话,需要写一个类,并且
继承MiddlewareMixin
from django.utils.deprecation import MiddlewareMixin
第一步:需要建立一个py文件夹来编写我们自定义的中间件,建议在应用层下面创建。
app-------》Middleware-----》middle.py
from django.utils.deprecation import MiddlewareMixin
class MyMiddleware1(MiddlewareMixin):
def process_request(self,request):
print('这是第一个中间件的process_request')
def process_response(self,request,response): # 响应
print('这是第一个中间件的process_response')
return response
class MyMiddleware2(MiddlewareMixin):
def process_request(self,request):
print('这是第二个中间件的process_request')
def process_response(self,request,response): # 响应
print('这是第二个中间件的process_response')
return response
第二步:在settings.py文件里面加入我们自定义的中间件
MIDDLEWARE = [
# settings这个列表中存储的其实就是一个个中间件的路径
'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',
#下面两个就是自定义的中间件路径地址
'app.Middleware.middle.MyMiddleware1',
'app.Middleware.middle.MyMiddleware2',
]
第三步:定义视图函数
'记得别忘记配置路由'
def func(request):
print('from func')
return HttpResponse('from func')
当我们浏览器朝服务端发送请求,必定会经过我们刚才定义的中间件
而process_request
方法的request则是请求,response则是视图函数返回的内容到了中间件里面,然后由中间件return出去。所以我们是可以在process_response
里面不写return视图函数返回的内容,自己定义内容返回。
从下图看,正常的情况下按照绿色的路线进行执行,假设中间件1有返回值,则按照红色的路线走,直接执行该类下的process_response方法返回,后面的其他中间件就不会执行。
也就是说中间件的process_request
方法使用了return
,那么其后面的中间件将不再执行,直接执行该中间件和其上面中间件的process_response
方法,最终将某个process_request
里面的return值返回给请求者。
由此总结:
- 中间件的process_request方法是在执行视图函数之前执行的。
- 当配置多个中间件时,会按照MIDDLEWARE中的注册顺序,也就是列表的索引值,从前到后依次执行的。
- 不同中间件之间传递的request都是同一个对象
多个中间件中的process_response方法是按照MIDDLEWARE中的注册顺序倒序执行的,也就是说第一个中间件的process_request方法首先执行,而它的process_response方法最后执行,最后一个中间件的process_request方法最后一个执行,它的process_response方法是最先执行的。
process_view方法
该方法格式:process_view(request, view_func, view_args, view_kwargs)
process_view方法的四个参数:
- request:HTTPRequest对象
- view_func:Django即将调用的视图函数
- view_args:将传递给视图的位置参数的元组
- view_kwargs:是将传递给视图的关键字参数的字典
view_args和view_kwargs都不包含第一个视图函数(request)
process_view方法是在视图函数之前,process_request方法之后执行的。
它应该返回None或一个HttpResponse对象,如果返回None,Django将继续处理这个请求,执行任何其他中间件的process_view方法,然后在执行相应的视图。如果它返回一个HttpResponse对象,Django不会调用适当的视图函数。它将执行中间件的process_response方法并将应用到该HttpResponse并返回结果。
自定义中间件:
记得需要注册自定义中间件
from django.utils.deprecation import MiddlewareMixin
class Md1(MiddlewareMixin):
def process_request(self,request):
print('M1请求来时,校验')
def process_response(self,reqeust,response):
print('M1返回数据时,对数据进行处理')
return response
def process_view(self,request,view_func,view_args,view_kwargs):
print('我在只给你view函数前执行!')
class Md2(MiddlewareMixin):
def process_reqeust(self,request):
print('M2请求来时,校验')
def process_response(self,request,response):
print('M2返回数据时,对数据进行处理')
return response
def process_view(self,request,view_func,view_args,view_kwargs):
pass
执行结果》》》》:
M1请求来时,校验
我在只给你view函数前执行!
from func
M2返回数据时,对数据进行处理
M1返回数据时,对数据进行处理
下图分析上面代码的执行过程:
当最后一个中间件的process_reqeust到达路由关系映射之后,返回到中间件1的process_view,然后依次往下,到达views函数,最后通过process_response依次返回到达用户。
注意:process_view如果有返回值,会越过其他的process_view以及视图函数,但是所有的process_response都还会执行。
process_exception
process_exception(self, request, exception)
该方法两个参数:
- 一个HttpRequest对象
- 一个exception是视图函数异常产生的Exception对象。
这个方法只有在视图函数中出现异常了才执行,它返回的值可以是一个None也可以是一个HttpResponse对象。如果是HttpResponse对象,Django将调用模板和中间件中的process_response方法,并返回给浏览器,否则将默认处理异常。如果返回一个None,则交给下一个中间件的process_exception方法来处理异常。它的执行顺序也是按照中间件注册顺序的倒序执行。
视图函数制造错误
def index(request):
print('index视图函数执行了')
lis = [1,2,3]
lis[4]
自定义中间件:
class Md1(MiddlewareMixin):
def process_request(self,request):
print("Md1请求")
def process_response(self,request,response):
print("Md1返回")
return response
def process_view(self, request, callback, callback_args, callback_kwargs):
print("md1 process_view...")
def process_exception(self,request,exception):
print("md1 process_exception...")
class Md2(MiddlewareMixin):
def process_request(self,request):
print("Md2请求")
def process_response(self,request,response):
print("Md2返回")
print(response.content)
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请求
Md2请求
md1 process_view...
md2 process_view...
index视图函数执行了
md2 process_exception...
Md2返回
b'list index out of range'
Md1返回
当process_exception进行return HttpResponse后,process_response方法就会拿到其返回的数据。
当views出现错误时流程图如下:
process_template_response(不常用)
该方法对视图函数返回值有要求,必须是一个含有render方法类的对象,才会执行此方法。
process_template_response 函数是在视图函数执行完后立即执行的
视图
def index(request):
print("这里是 index 页面")
repsponse = HttpResponse("这里是主页面 index")
def render():
print("这里是 index 函数里的 render 方法")
return HttpResponse("index")
repsponse.render = render
return repsponse
自定义中间件
class Md2(MiddlewareMixin):
def process_request(self,request):
print("Md2请求")
def process_response(self,request,response):
print("Md2返回")
return response
def process_view(self, request, view_func, view_args, view_kwargs):
print(view_func)
print("md2 process_view...")
def process_template_response(self, request, response):
print("视图函数执行完毕,且返回了render")
return response
执行结果》》》》:
Md2请求
md2 process_view...
这里是 index 页面
视图函数执行完毕,且返回了render
这里是 index 函数里的 render 方法
Md2返回