django中的中间件贯穿一个请求的始终,请求进来会被中间件的process_request拦截,执行视图函数时会被中间件的process_view拦截,产生错误异常时会被中间件的process_exception拦截,模版渲染时会被中间件的process_template_response拦截,返回响应时会被中间件的process_response拦截。因此在django中中间件是一个非常重要的模块,我们可以自定义一些中间件来满足我们项目开发中的各种需求。
中间件为我们提供了以上5个方法,各个方法的执行时机不同,除了执行时机还有一些需要注意的地方:
process_request(self,request):
如果此方法有返回值,且返回值为None时django会继续执行下面的中间件,但如果此方法返回了HttpResponse对象,那么Django将不会执行其他的中间件,只会执行当前中间件的process_response方法,并返回该HttpResponse对象。
process_view(self,request,view_func,view_args,view_kwargs):
此方法会在Django确定了将要执行的视图函数(view_func)之后执行,但此时还没有执行视图函数,其中view_args表示视图函数要接收的元组参数,view_kwargs表示视图函数要接受的字典参数,两者均不包含request参数,request参数一般作为第一个参数传入。同样该方法如果返回HttpResponse对象,Django将不会执行任何其它的中间件以及相应的view,只会执行当前中间件的process_response方法,并返回该HttpResponse对象。
此方法执行步骤:
(1)执行完所有中间件的request方法‘
(2)url匹配成功
(3)拿到视图函数的名称、参数,(注意不执行)再执行process_view()方法
(4)最后去执行视图函数
当我们在此方法中把视图函数进行返回,那么之后的process_view()都不会被执行,而是直接跳转到最后一个中间的process_response()进行逐一返回
process_exception(self, request, exception):
exception表示view视图抛出的异常对象,此方法会在请求发生错误并且未捕获的情况下执行,这个钩子可以用来发送错误通知,将现场相关信息输出到日志文件,或者甚至尝试从错误中自动恢复。process_exception应该返回None或者HttpResponse对象,如果返回HttpResponse对象,Django将使用该response对象,而短路框架内置的异常处理机制。
该方法执行步骤:
(1)执行完所有 request 方法;
(2)执行所有 process_view方法;
(3)如果视图函数出错,执行process_exception方法,如果第一个中间件的 process_exception方法有了返回值就不再执行其他中间件process_exception,直接执行response方法;
(4)执行所有response方法;
(5)返回process_exception的返回值。
process_template_response(self, request, response):
默认不执行,只有在视图函数的返回结果对象中有render方法才会执行,并把对象的render方法的返回值返回给用户(注意不返回视图函数的return的结果了,而是返回视图函数 return值(对象)中render方法的结果),该方法必须返回response,否则报错。
process_response(self, request, response):
此方法的调用时机是在view视图返回response之后。使用该方法我们可以修改返回的response的内容,例如内容压缩。process_response()必须返回一个HttpResponse对象,这个 response 对象可以是传入函数的那一个原始对象(通常已被修改),也可以是全新生成的。
Django的settings中默认配置了几项中间件:
MIDDLEWARE = [
# 做了一些安全处理的中间件。比如设置xss防御的请求头,做了http协议转https协议的工作等。
'django.middleware.security.SecurityMiddleware',
# session中间件,会给request添加一个处理好的session对象。
'django.contrib.sessions.middleware.SessionMiddleware',
# 通用中间件,可以限制settings.DISALLOWED_USER_AGENTS中指定的请求头来访问本站,DISALLOWED_USER_AGENTS是一个正则表达式的列表,
# 如果开发者在定义url时最后有斜杠,但用户在访问的时候没有添加这个斜杠,那么该中间件会自动重定向到加了斜杠的url上。
'django.middleware.common.CommonMiddleware',
# csrf保护的中间件
'django.middleware.csrf.CsrfViewMiddleware',
# 会给request添加一个user对象的中间件
'django.contrib.auth.middleware.AuthenticationMiddleware',
# 消息处理相关的中间件
'django.contrib.messages.middleware.MessageMiddleware',
# 做了clickjacking攻击的保护
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
Django中还有其他的内置中间件,例如django.middleware.gzip.GZipMiddleware
可以将响应数据进行压缩。如果内容长度小于200个长度,那么就不会压缩。django.middleware.cache.UpdateCacheMiddleware
,django.middleware.cache.FetchFromCacheMiddleware
可作为缓存中间件用来缓存一些页面。
Django内之中间件放置顺序:
SecurityMiddleware:应该放到最前面。因为这个中间件并不需要依赖任何其他的中间件。如果你的网站同时支持http协议和https协议,并且你想让用户在使用http协议的时候重定向到https协议,那么就没有必要让他执行下面一大串中间件再重定向,这样效率更高。
UpdateCacheMiddleware:应该在SessionMiddleware, GZipMiddleware, LocaleMiddleware之前。
GZipMiddleware。
ConditionalGetMiddleware。
SessionMiddleware。
LocaleMiddleware。
CommonMiddleware。
CsrfViewMiddleware。
AuthenticationMiddleware。
MessageMiddleware。
FetchFromCacheMiddleware。
FlatpageFallbackMiddleware。
RedirectFallbackMiddleware。
以上都是Django自带的中间件,我们还可以自定义一些中间,中间件可以在任意目录下自定义,只需要在settings中导入中间件路径进行激活即可,但一般我们会需要用到自定义中间件的app下自定义。
中间件实际就是一个装饰器,因此我们可以使用闭包函数来进行自定义,或者使用类自定义。
函数式自定义:
首先在app内创建一个middleware.py的文件,专门用来存放自定义中间件。
# 函数接收一个get_response对象
def myMiddleware(get_response):
# 中间件初始化时执行的代码块,即项目启动时就会执行
print("中间件init初始化")
def middleware(request):
# 视图函数执行之前执行的代码,即process_request()执行的代码
print("中间件process_request()执行")
response = get_response(request) # 视图执行
# 视图函数执行之后执行的代码,即process_response()执行的代码
print("中间件process_response()执行")
return response
return middleware
在settings中激活中间件:
启动项目并访问登录界面:
使用类自定义中间件:
# 类自定义中间件主要是重写类的__call__方法
class MyMiddleware(object):
def __init__(self,get_response):
self.get_response = get_response
# 中间件初始化时执行的代码块,即项目启动时就会执行
def __call__(self, request):
# 视图函数执行之前执行的代码,即process_request()执行的代码
print("中间件process_request()执行")
response = self.get_response(request) # 视图执行
# 视图函数执行之后执行的代码,即process_response()执行的代码
print("中间件process_response()执行")
return response
在seetings中激活中间件:
可以看到函数自定义中间件和类自定义中间件实现的效果是完全一样的。但是函数式自定义不能够定义process_view、process_exception以及process_template_response,想要定义这三个方法需要在类中。
例如:
class MyMiddleware(object):
def __init__(self,get_response):
print("中间件init初始化")
self.get_response = get_response
# 中间件初始化时执行的代码块,即项目启动时就会执行
def __call__(self, request):
# 视图函数执行之前执行的代码,即process_request()执行的代码
print("中间件process_request()执行")
response = self.get_response(request)
# 视图函数执行之后执行的代码,即process_response()执行的代码
print("中间件process_response()执行")
return response
def process_exception(self, request, exception):
print(exception)
当视图中没有异常时,process_exception()方法不会执行,当视图中出现异常时:
此时process_execption会执行:
继承MiddlewareMixin类自定义中间件:
对于类自定义中间件其实还有一种方法,即继承MiddlewareMixin类,但这个类被放到了deprecation模块里了,deprecation意为不赞成,即官方不赞成我们使用,说不定哪天这个类就不复存在了。此方法是Django1.10之前使用的自定义中间件的方法。
from django.utils.deprecation import MiddlewareMixin
class MyMiddleware(MiddlewareMixin):
def __init__(self,get_response):
# 中间件初始化时执行的代码块,即项目启动时就会执行
self.get_response = get_response
super(MyMiddleware, self).__init__(get_response)
print("中间件init初始化")
def process_request(self,request):
print("中间件process_request()执行")
def process_response(self,request, response):
print("中间件process_response()执行")
return response
以上就是自定义中间件的三种方法,推荐使用前两种。Django的中间件是一个轻巧的低级“插件”系统,用于全局改变Django的输入和输出,因此在实际编程过程中会经常用到,理解中间件以及掌握中间件的自定义是非常有必要的,可以为我们解决许多繁琐冗余的工作。