我们在使用Python的一些库时,会遇到中间件这个概念,比如scrapy和Django,那么什么是中间件呢?
中间件就是在目标和结果之间进行的额外处理过程,在Django中就是request和response之间进行的处理,相对来说实现起来比较简单,但是要注意它是对全局有效的,可以在全局范围内改变输入和输出结果,因此需要谨慎使用,否则不仅会造成难以定位的错误,而且可能会影响整体性能。
如果想要修改HttpRequest或者HttpResponse,就可以通过中间件来实现。
在Django中自定义中间件是非常简单的,在settings.py中有一个配置项:
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',
]
只要把添加的中间件配置在这里就可以了。每一个中间件都是一个类,多个中间件可以写在同一个文件,也可以在独立文件中。每个中间件可以包含五个方法:
process_request(self,request)
process_view(self, request, callback, callback_args, callback_kwargs)
process_template_response(self,request,response)
process_exception(self, request, exception)
process_response(self, request, response)
我在网上找到这么一张图片,说明了请求的数据流在Django中间件当中的执行流程
中间件函数执行流程
以上这些执行函数将返回None或者HttpResponse对象,如果返回None,则交给下一个中间件的对应函数处理;如果返回HttpResponse对象,则将其返回给用户
在这些中间件的执行函数中,我们最常用的就是process_request和process_response函数,通常用来在视图函数处理前和视图函数处理后执行一些相应的操作,这个要根据我们的业务需求,选择不同的处理过程。例如:进行登陆认证,因为必须要在视图函数处理前进行认证,我们可以在process_request中处理;携带认证cookies信息,就可以在process_response函数中给response对象增加指定cookies值。
from django.utils.deprecation import MiddlewareMixin
class MyCustomMiddleware1(MiddlewareMixin):
def process_request(self, request):
print('MyCustomMiddleware1')
def process_response(self, request, response):
print('返回 MyCustomMiddleware1')
return response
class MyCustomMiddleware2(MiddlewareMixin):
def process_request(self, request):
print('MyCustomMiddleware2')
def process_response(self, request, response):
print('返回 MyCustomMiddleware2')
return response
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',
'MyMiddleware.MyCustomMiddleware1',
'MyMiddleware.MyCustomMiddleware2'
]
输出结果:
MyCustomMiddleware1
MyCustomMiddleware2
返回 MyCustomMiddleware2
返回 MyCustomMiddleware1
def process_request(self, request):
session_key = request.COOKIES.get(settings.SESSION_COOKIE_NAME)
request.session = self.SessionStore(session_key)
在process_response函数中,给response对象设置SESSION_COOKIE_NAME值和过期时间等。
response.set_cookie(
settings.SESSION_COOKIE_NAME,
request.session.session_key, max_age=max_age,
expires=expires, domain=settings.SESSION_COOKIE_DOMAIN,
path=settings.SESSION_COOKIE_PATH,
secure=settings.SESSION_COOKIE_SECURE or None,
httponly=settings.SESSION_COOKIE_HTTPONLY or None,
samesite=settings.SESSION_COOKIE_SAMESITE
)
if 'HTTP_USER_AGENT' in request.META:
for user_agent_regex in settings.DISALLOWED_USER_AGENTS:
if user_agent_regex.search(request.META['HTTP_USER_AGENT']):
raise PermissionDenied('Forbidden user agent')
检查是否需要添加/,主要是根据settings中AppEND_SLASH配置
if self.should_redirect_with_slash(request):
path = self.get_full_path_with_slash(request)
else:
path = request.get_full_path()
在process_response函数中,会判断是否需要把404的请求重新定向到我们需要的页面
{% if messages %}
<ul class="messages">
{% for message in messages %}
<li{% if message.tags %} class="{{ message.tags }}" {% endif %}>
{% if mesage.level == DEFAULT_MESSAGE_LEVELS.ERROR %}Important: {% endif %}
{{ message }}
</li>
{% endfor %}
</ul>
{% endif %}