# 요청 발생 시 위에서 아래로 진행되면서 process_request() 실행
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_response() 실행
def __call__(self, request):
...
response = None
if hasattr(self, 'process_request'):
response = self.process_request(request)
response = response or self.get_response(request)
if hasattr(self, 'process_response'):
response = self.process_response(request, response)
return response
class CommonMiddleware(MiddlewareMixin):
def process_request(self, request: WSGIRequest): -> None | HttpResponse
...
def process_response(self, request: WSGIRequest, response: HttpResponse): -> HttpResponse
...
def process_view(self, request: WSGIRequest, callback: Callable, callback_args, callback_kwargs): -> None | HttpResponse
...
미들웨어 클래스가 역순으로 호출되면서 process_request, process_response를 제외한 나머지 “process_”는 load_middleware 메소드에서 적절한 객체 속성에 쌓임
# django.core.handlers.wsgi.WSGIHandler 에서 BaesHandler.get_response() 호출
# from django.core.handlers.base import BaseHandler
class BaseHandler:
_view_middleware = None
_template_response_middleware = None
_exception_middleware = None
_middleware_chain = None
# 응답 로직을 실행하진 않고, 미들웨어 메소드 셋팅만 진행
def load_middleware(self, is_async=False):
self._view_middleware = []
self._template_response_middleware = []
self._exception_middleware = []
# 초기 get_response: Callable = BaseHandler._get_response
get_response = self._get_response_async if is_async else self._get_response
# 처음 stack에 BaseHandler._get_response 쌓임
handler = convert_exception_to_response(get_response)
for middleware_path in reversed(settings.MIDDLEWARE):
...
if hasattr(mw_instance, 'process_view'):
self._view_middleware.insert(
0,
self.adapt_method_mode(is_async, mw_instance.process_view),
)
if hasattr(mw_instance, 'process_template_response'):
self._template_response_middleware.append(
self.adapt_method_mode(is_async, mw_instance.process_template_response),
)
if hasattr(mw_instance, 'process_exception'):
self._exception_middleware.append(
self.adapt_method_mode(False, mw_instance.process_exception),
)
# convert_exception_to_response 함수에 의해서 stack(linked list에 가까울듯)처럼 get_response(콜러블 객체)가 쌓임
# 이름 때문에 혼동될 수 있지만 mw_instance가 convert_exception_to_response의 get_response 매개 변수에 들어감
# mw_instance.get_response 속성과 별개(헷갈림 주의)
handler = convert_exception_to_response(mw_instance)
handler_is_async = middleware_is_async
handler = self.adapt_method_mode(is_async, handler, handler_is_async)
# reversed(settings.MIDDLEWARE)에 의해 settings.MIDDLEWARE 리스트의 마지막 미들웨어가 mw_instance1
# handler에는 mw_instanceX(MIDDLEWARE 리스트의 첫 번째)가 할당됨
# mw_instanceX.get_response -> mw_instance3
# mw_instance3.get_response -> mw_instance2
# mw_instance2.get_response -> mw_instance1
# mw_instance1.get_response -> BaseHandler._get_response 이런 구조가 됨
self._middleware_chain = handler
# stack 마지막에 위치하는 메소드
def _get_response(self, request):
response = None
callback, callback_args, callback_kwargs = self.resolve_request(request)
# view middleware 적용
for middleware_method in self._view_middleware:
response = middleware_method(request, callback, callback_args, callback_kwargs)
if response:
break
if response is None:
# wrapped_callback: APIView에 정의된 http method
wrapped_callback = self.make_vinew_atomic(callback)
...
try:
# http method 호출 -> HttpResponse 반환
response = wrapped_callback(request, *callback_args, **callback_kwargs)
...
return response

# from django.utils.deprecation import MiddlewareMixin
class MiddlewareMixin:
sync_capable = True
async_capable = True
def __init__(self, get_response: Callable):
...
self.get_response = get_response
def __call__(self, request):
...
response = None
if hasattr(self, 'process_request'):
response = self.process_request(request)
# load_middleware가 실행될 때 self.get_response에 이전 middleware(mw_instance)가 저장됨
# self.get_response = 이전 mw_instance가 들어있고,
# 마지막 mw_instance.get_response에는 BaseHandler._get_response 메소드가 들어있음
# 미들웨어의 __call__ 메소드는 WSGIHandler.get_response 안에서 호출됨(middleware.get_response 아님)
response = response or self.get_response(request)
if hasattr(self, 'process_response'):
response = self.process_response(request, response)
return response
# from django.core.handlers.wsgi import WSGIHandler
class WSGIHandler(base.BaseHandler):
request_class = WSGIRequest
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.load_middleware() # 미들웨어 메소드 체인 셋팅
def __call__(self, environ, start_response):
set_script_prefix(get_script_name(environ))
signals.request_started.send(sender=self.__class__, environ=environ)
request = self.request_class(environ)
response = self.get_response(request)
class BaseHandler:
...
def get_response(self, request):
set_urlconf(settings.ROOT_URLCONF)
# middleware chain 실행: 실제 응답값이 만들어지는 시점(아래 참고)
response = self._middleware_chain(request)
response._resource_closers.append(request.close)
if response.status_code >= 400:
log_response(
'%s: %s', response.reason_phrase, request.path,
response=response,
request=request,
)
return response
def convert_exception_to_response(get_response):
if:
...
else:
@wraps(get_response)
def inner(request):
try:
# get_response() == mw_instance.__call__ 메소드 호출
response = get_response(request)
except Exception as exc:
response = response_for_exception(request, exc)
return response
return inner
BaseHandler._middleware_chain(request) == convert_exception_to_response.inner(request) 호출
mw_instanceX.call(request) 호출 → mixin.call()의 response or self.get_response(request) 구문에서 self.get_response(request) 호출
mw_instance3.call(request) 호출 → mixin.call()의 response or … 구문에서 self.get_response(request) 호출
반복 후 mw_instance1.call(request) 호출 → BaseHandler._get_response(request) 호출
→ 요청된 APIView의 http 메소드 실행 → 응답값 반환
response = self._middleware_chain(request) 구문 실행 완료
claude