Django中间件的原理
一般中间件都是通过闭包来实现,django是通过装饰器(也是闭包的一个类型)实现。本质类似是入栈操作FILO
- 首先功过WSGIHandler的实例调用
self.load_middleware()
,加载父类的Basehandler.load_middleware()
方法
class WSGIHandler(base.BaseHandler):
request_class = WSGIRequest
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.load_middleware()
套娃的思想是传入callable通过装饰器返回的是嵌套的callable
-
重点是看如何实现套娃的,下面的mw_instance是中间件实例,也就是callable
class BaseHandler: def load_middleware(self): handler = self.get_response for middleware in reversed(MIDDLEWARE): mw_instance = middleware(handler) # handler是函数callable,mw_instance有__call__也是callable handler = convert_exception_to_response(mw_instance) self._middleware_chain = handler def get_response(self, request): print("get response %s" % request) def convert_exception_to_response(get_response): @wraps(get_response) def inner(request): try: response = get_response(request) except Exception as exc: response = "exc %s" % exc return response return inner
完整查看示例
from functools import wraps
def convert_exception_to_response(get_response):
@wraps(get_response)
def inner(request):
try:
response = get_response(request)
except Exception as exc:
response = "exc %s" % exc
return response
return inner
class Middleware1:
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
print(self.__class__.__name__, request)
self.get_response(request)
class Middleware2:
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
print(self.__class__.__name__, request)
self.get_response(request)
class Middleware3:
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
print(self.__class__.__name__, request)
self.get_response(request)
MIDDLEWARE = [Middleware1, Middleware2, Middleware3]
class BaseHandler:
def load_middleware(self):
handler = self.get_response
for middleware in reversed(MIDDLEWARE):
mw_instance = middleware(handler)
handler = convert_exception_to_response(mw_instance)
self._middleware_chain = handler
def get_response(self, request):
print("get response %s" % request)
if __name__ == '__main__':
b = BaseHandler()
b.load_middleware()
request = "request"
b._middleware_chain(request)
# 执行_middleware_chain(request) 输出
#Middleware1 request
#Middleware2 request
#Middleware3 request
#get response request