django

Django core - WSGI

Jueuunn7 2024. 10. 21. 02:15

 

1. WSGI

서버에 요청이 들어오면 nginx나 apache와 같은 웹 서버들은 애플리케이션을 호출해야 합니다.

하지만 보통의 웹 서버들은 애플리케이션을 이해하고 호출하는 기능이 없기 때문에 중간에 중개해 주는 무엇이 필요합니다.

WSGI는 pep 333을 기반으로 만들어진 웹 서버와 파이썬 애플리케이션을 하나의 체인으로 연결해 통신하게 하는 인터페이스입니다.

먼저 클라이언트에서 온 요청이 웹 서버가 받고, 그 요청을 WSGI에 전달합니다. 서버단에서 작업이 필요한 경우에는 WSGI가 애플리케이션에 요청을 전송하고 애플리케이션에서 로직이 처리된 후에 WSGI middleware을 통해 응답됩니다.

 

2. WSGI middleware

WSGI middleware은 WSGI를 사용한 구현체입니다.

미들웨어가 직접적으로 웹 서버와 애플리케이션을 연결해 주는 역할을 하며 그 종류에는 Gunicorn, uWSGI 등등 여러 가지 있습니다.

nginx에 WSGI module이 바인드 되고 application이 WSGI process 위에 올라가는 구조를 갖고 있습니다.

WSGI module, process를 함께 WSGI middleware라고 부르고 보라색으로 표시된 부분 즉 WSGI process까지 WAS라고 부릅니다.

WSGI middleware은 로드밸런싱등 여러 기능들을 기본으로 탑재되어 있습니다.

 

3. Django wsgi.py

import os

from django.core.wsgi import get_wsgi_application

os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'project.settings')

application = get_wsgi_application()

Django 애플리케이션은 wsgi 혹은 asgi 위에서 동작합니다. wsgi.py는 애플리케이션과 웹 서버를 연결해 주는 역할을 하며 runserver(로컬 개발 환경)과 프로덕션 서버에서 모두 사용됩니다. 

코드를 간단하게 설명해 보면 DJANGO_SETTINGS_MODULE라는 환경변수에 settings.py의 위치를 넣어 기본 설정파일을 지정해 줍니다.

application 에는 get_wsgi_application()이 담깁니다.

import django
from django.core.handlers.wsgi import WSGIHandler

def get_wsgi_application():
    django.setup(set_prefix=False)
    return WSGIHandler()

 

get_wsgi_application 내부에서는 장고를 셋업하고 WSGIHandler를 반환합니다.

 

4. 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)

        response._handler_class = self.__class__

        status = "%d %s" % (response.status_code, response.reason_phrase)
        response_headers = [
            *response.items(),
            *(("Set-Cookie", c.output(header="")) for c in response.cookies.values()),
        ]
        start_response(status, response_headers)
        if getattr(response, "file_to_stream", None) is not None and environ.get(
            "wsgi.file_wrapper"
        ):
            response.file_to_stream.close = response.close
            response = environ["wsgi.file_wrapper"](
                response.file_to_stream, response.block_size
            )
        return response

 

4-1. __init__

BaseHandler를 초기화하고 middleware를 로드합니다. 부모클래스인 BaseHandler는 장고 settings 파일에서 넣어준 middleware들을 실행합니다.

 

4-2. __call__

call 매직메서드는 요청을 처리할 때 사용됩니다.

주요 로직을 살펴보면

request_class()

자신 클래스의 WSGIRequest 객체를 생성해서 요청 객체를 생성합니다. 

WSGIRequest에 HttpRequest에게 상속받은 필드중 일부를 작성했습니다.

WSGIHandler에 get_request_class를 호출할 때 WSGIRequest가 초기화됩니다. HTTP Request 패킷 자체를 직접 사용할 수 없기에 WSGIRequest라는 객체에 담고 Django의 View 계층으로 전송하면서 마치 orm처럼 HTTP 요청을 파이썬 객체로 쉽게 사용할 수 있게 도와줍니다. Django Rest Framework에서는 Django에 HTTPRequest를 감싸는 Request 객체를 새로 만들어 사용합니다. 이 객체는 다음 메서드인 get_response 메서드에 request로 인자에 들어갑니다.

get_response()

요청 객체를 전달하고 요청에 대한 응답을 생성합니다. 이때 라우팅, view 로직 등이 실행됩니다.

response

status와 cookie를 설정하고 WSGI에 status code와 cookie를 설정하며 응답을 시작합니다. 파일 스트리밍인 경우에는 wsgi.file_wrapper를 따로 사용하고 아닌 경우에는 WSGI에 응답 객체를 반환하며 클라이언트에게 전송되며 응답이 종료됩니다.

 

 

 

'django' 카테고리의 다른 글

Django - Trailing Slash  (1) 2024.12.02
Django - DB Connection  (0) 2024.10.27
DRF Serializer  (2) 2024.09.18
Django ORM - Transaction  (0) 2024.08.06
Django - Nginx + Gunicorn으로 배포하기  (1) 2024.06.21