Django中間件的原理
一般中間件都是通過閉包來實現(xiàn),django是通過裝飾器(也是閉包的一個類型)實現(xiàn)田盈。本質(zhì)類似是入棧操作FILO
- 首先功過WSGIHandler的實例調(diào)用
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
-
重點是看如何實現(xiàn)套娃的,下面的mw_instance是中間件實例脱吱,也就是callable
class BaseHandler: def load_middleware(self): handler = self.get_response for middleware in reversed(MIDDLEWARE): mw_instance = middleware(handler) # handler是函數(shù)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)
# 執(zhí)行_middleware_chain(request) 輸出
#Middleware1 request
#Middleware2 request
#Middleware3 request
#get response request