按照settings.MIDDLEWARE的顺序,由上至下执行,如:
MIDDLEWARE = [ "django.middleware.security.SecurityMiddleware", "django.middleware.common.CommonMiddleware", "django.middleware.clickjacking.XFrameOptionsMiddleware", "apps.api.middleware_mgr.Middleware", ] # django/core/handlers/base.py class BaseHandler(object): def load_middleware(self): # _get_response会逐层调用中间件的process_view方法 # 然后处理view,即中间件的最中心 handler = convert_exception_to_response(self._get_response) for middleware_path in reversed(settings.MIDDLEWARE): # 按照 MIDDLEWARE 的逆序生成中间件实例 middleware = import_string(middleware_path) try: # 这里将中间件实例当做函数调用,即MiddlewareMixin的__call__方法 # 由于是按逆序生成中间件实例,因此是一层层外套用 mw_instance = middleware(handler) except MiddlewareNotUsed as exc: ... if hasattr(mw_instance, 'process_view'): # process_view是正序调用 self._view_middleware.insert(0, mw_instance.process_view) if hasattr(mw_instance, 'process_template_response'): # process_template_response 和 process_exception 都是逆序调用 self._template_response_middleware.append(mw_instance.process_template_response) if hasattr(mw_instance, 'process_exception'): self._exception_middleware.append(mw_instance.process_exception) # 这边将当前层的中间件实例作为外一层的get_response函数 # 传入MiddlwareMixin的__init__中 # 这样保证了process_request和process_response的正确调用顺序 handler = convert_exception_to_response(mw_instance) 中间件发生错误后的返回中间件发生错误后将直接返回一个HttpResponse对象,下层中间件将不会被执行
class MiddlewareMixin(object): def __init__(self, get_response=None): self.get_response = get_response super(MiddlewareMixin, self).__init__() def __call__(self, request): response = None if hasattr(self, 'process_request'): response = self.process_request(request) # 当response不为空时,将不会执行下层中间件 if not response: # 没有发生错误,继续执行下层中间件 response = self.get_response(request) # 直接执行当前层的proces_response,并返回响应 if hasattr(self, 'process_response'): response = self.process_response(request, response) return response 自定义中间件 五大钩子函数 表头 表头 表头 表头process_request 请求刚到来,执行视图之前 配置列表的正序 None或者HttpResponse对象
process_response 视图执行完毕,返回响应时 逆序 HttpResponse对象
process_view process_request之后,路由转发到视图,执行视图之前 正序 None或者HttpResponse对象
process_exception 视图执行中发生异常时 逆序 None或者HttpResponse对象
process_template_response 视图刚执行完毕,process_response之前 逆序 实现了render方法的响应对象
例子
注意middleware方法的输入参数都是固定的
# utils/my_middleware.py from django.utils.deprecation import MiddlewareMixin class MyMiddleware1(MiddlewareMixin): def __str__(self): return "MyMiddleware1" def process_request(self, request): print(self, " processing request...") def process_view(self, request, view_func, view_args, view_kwargs): print(self, " processing view...") def process_response(self, request, response): print(self, " processing response...") return response def process_exception(self, request, exception): print(self, " processing exception...") class MyMiddleware2(MiddlewareMixin): def __str__(self): return "MyMiddleware2" def process_request(self, request): print(self, " processing request...") def process_view(self, request, view_func, view_args, view_kwargs): print(self, " processing view...") def process_response(self, request, response): print(self, " processing response...") return response def process_exception(self, request, exception): print(self, " processing exception...") # 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', 'utils.my_middleware.MyMiddleware1', 'utils.my_middleware.MyMiddleware2' ] # urls.py from django.conf.urls import url from demo.views import mid_test urlpatterns = [ url(r"^midtest/", mid_test), ] # views.py from django.http import HttpResponse def mid_test(request): print('in mid_test view') return HttpResponse('ok')