Django
[Django] WSGI handlers 분석해보기!
chief
2022. 9. 15. 14:00
반응형
🚀 들어가며...
- 미들웨어를 공부하다가 장고에서 미들웨어는 request는 순서대로 들어오나 response는 역순으로 리턴되는 부분에서 왜 이렇게 설계를 했을까 하는 궁금증이 들어서 간단히 site-packages/django/core/handlers/base.py에 있는 소스를 분석해 보았습니다.
📑 내용
우선 저의 궁금증을 해결해줄 소스를 먼저 보여드리겠습니다.
def load_middleware(self):
"""
Populate middleware lists from settings.MIDDLEWARE_CLASSES.
Must be called after the environment is fixed (see __call__ in subclasses).
"""
self._view_middleware = []
self._template_response_middleware = []
self._response_middleware = []
self._exception_middleware = []
request_middleware = []
for middleware_path in settings.MIDDLEWARE_CLASSES:
mw_class = import_string(middleware_path)
try:
mw_instance = mw_class()
except MiddlewareNotUsed as exc:
if settings.DEBUG:
if six.text_type(exc):
logger.debug('MiddlewareNotUsed(%r): %s', middleware_path, exc)
else:
logger.debug('MiddlewareNotUsed: %r', middleware_path)
continue
if hasattr(mw_instance, 'process_request'):
request_middleware.append(mw_instance.process_request)
if hasattr(mw_instance, 'process_view'):
self._view_middleware.append(mw_instance.process_view)
if hasattr(mw_instance, 'process_template_response'):
self._template_response_middleware.insert(0, mw_instance.process_template_response)
if hasattr(mw_instance, 'process_response'):
self._response_middleware.insert(0, mw_instance.process_response)
if hasattr(mw_instance, 'process_exception'):
self._exception_middleware.insert(0, mw_instance.process_exception)
# We only assign to this when initialization is complete as it is used
# as a flag for initialization being complete.
self._request_middleware = request_middleware
이 부분인데 여기서 settings.MIDDLEWARE_CLASSES에서 base.py에 미리 선언해둔 MIDDLEWARE_CLASSES에 미들웨어들을
가져와서 반복문을 돌며 템플릿용/리퀘스트용/리스폰스용을 정리하면서 response에 담습니다.
이 때, insert문을 이용하여 추가할 항목들을 리스트 0번째에 계속 밀어넣기 때문에 response에는 역순으로 담기는 것입니다. 그 다음은..
def get_response(self, request):
"Returns an HttpResponse object for the given HttpRequest"
# Setup default url resolver for this thread, this code is outside
# the try/except so we don't get a spurious "unbound local
# variable" exception in the event an exception is raised before
# resolver is set
(생략)
try:
response = None
# Apply request middleware
for middleware_method in self._request_middleware:
response = middleware_method(request)
if response:
break
if response is None:
if hasattr(request, 'urlconf'):
# Reset url resolver with a custom urlconf.
urlconf = request.urlconf
urlresolvers.set_urlconf(urlconf)
resolver = urlresolvers.RegexURLResolver(r'^/', urlconf)
resolver_match = resolver.resolve(request.path_info)
callback, callback_args, callback_kwargs = resolver_match
request.resolver_match = resolver_match
# Apply 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 = self.make_view_atomic(callback)
try:
response = wrapped_callback(request, *callback_args, **callback_kwargs)
이제 위 소스와 같이 바로 밑에서 함수를 실행하게 되는데, WSGI가 쓰레드를 돌다가 소켓에서 리퀘스트를 받으면
make_view_atomic 함수에서 미들웨어 함수를 일렬로 실행하게 됩니다. (단, 미들웨어를 종류별로 돌긴 합니다.)
def make_view_atomic(self, view):
non_atomic_requests = getattr(view, '_non_atomic_requests', set())
for db in connections.all():
if (db.settings_dict['ATOMIC_REQUESTS']
and db.alias not in non_atomic_requests):
view = transaction.atomic(using=db.alias)(view)
return view
위에 소스처럼 말이죠.
하지만.. 미들웨어를 response에 담을때 왜 0번째에 밀어넣는지에 대한 설계이유에 대해선 아무리 구글링과 공식문서를 찾아도 나오지가 않아서 궁금증이 해결되지는 않고 분석만 하다가 끝났습니다 ㅠㅠ
🙋🏻♂️ 후기
혹시나 저의 궁금증에 대해 조금이나마 정보를 가지고 계신 분들은 댓글로 공유 부탁드립니다!
그리고 위에 분석은 저의 생각을 토대로 분석하였기 때문에 잘못된 부분에 대한 피드백은 언제나 환영입니다! 감사합니다.
🔗 참고한 글
https://docs.djangoproject.com/ko/4.1/topics/http/middleware/
Middleware | Django 문서 | Django
Django The web framework for perfectionists with deadlines. Overview Download Documentation News Community Code Issues About ♥ Donate
docs.djangoproject.com
반응형