客户端通过http协议发送请求报文到web服务器, web服务器解析请求报文, 通过wsgi协议把解析好的请求发送到Django项目, Django项目产生request对象, 依次的从上到下调用中间件中的process_request方法, 进行url匹配, 依次从上到下调用中间件中的process_view方法, 调用视图, 依次从下到上的调用中间件中的process_response方法特别注意的是: 在依次调用中间件中的process_request, process_view, process_response方法时, 如果process_request方法中返回了响应对象, 那么后续的url匹配, process_view方法的调用以及视图的调用都不会走, 会直接的跳到process_response这个方法中执行, 同样的如果执行到中间件的process_view方法中返回了响应对象, 那么不会再去调用视图, 直接跳到process_response方法中执行, process_response返回响应通过wsgi协议给web服务器, web服务器构造响应报文, 再通过http协议发送响应报文到客户端
django中自带的中间件, 比较熟悉的有CsrfViewMiddleware, 我们可以去看一下, 自带的中间件怎么实现的
from django.middleware.csrf import CsrfViewMiddleware
from django.http import HttpResponse
from django.utils.deprecation import MiddlewareMixin
# 需求: 黑名单, 不允许访问任何视图函数
class BlackIpMiddleware:
"""黑名单过滤中间件"""
# 测试添加本地为黑名单
BLACK_IP = ['127.0.0.1']
def __init__(self, get_response=None):
"""django 1.10之前, 服务器响应第一个请求时才会调用, 之后启动应用即调用"""
print('__init__')
self.get_response = get_response
super().__init__()
def __call__(self, request):
"""每个请求调用一次的__ call __()"""
response = None
if hasattr(self, 'process_request'):
response = self.process_request(request)
if not response:
response = self.get_response(request)
if hasattr(self, 'process_response'):
response = self.process_response(request, response)
return response
def process_request(self, request):
"""在产生request对象, 进行url匹配之前调用"""
print('process_request')
def process_view(self, request, view_func, *args, **kwargs):
"""在url匹配后, 调用视图函数之前"""
# 获取用户ip
print('process_view')
user_ip = request.META['REMOTE_ADDR']
if user_ip in self.BLACK_IP:
return HttpResponse('Forbidden
')
def process_response(self, request, response):
"""视图函数调用之后, 内容返回给浏览器之前"""
print('process_response')
return response
def process_exception(self, request, exception):
"""视图函数出现异常, 会调用这个函数"""
print(exception)
print('exception')
过滤效果入下:
上面的代码我导入了一个扩展类, 上面的中间件类中的__init__()和__call__()在扩展类中都已经实现了, 可以直接继承这个扩展类, 直接编辑中间件中的方法即可