티스토리 뷰

반응형

🚀  들어가며...

  • 미들웨어를 공부하다가 장고에서 미들웨어는 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

 

반응형
댓글
반응형
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2025/01   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
글 보관함