Django에서 커스텀 미들웨어 구현하기

Django 미들웨어란?

Django 미들웨어는 요청과 응답 사이에 위치하여 처리 과정을 가로채거나 수정할 수 있는 강력한 시스템입니다. 이를 통해 인증, 로깅, 보안 검사 등 다양한 기능을 뷰(View) 코드에 영향을 주지 않고도 구현할 수 있습니다. 미들웨어는 애플리케이션의 전반적인 흐름에 개입하면서도 모듈화된 방식으로 동작하므로 유지보수가 용이합니다.

미들웨어의 주요 메서드

Django 미들웨어 클래스는 특정 단계에서 자동으로 호출되는 여러 훅(hook) 메서드를 제공합니다. 각 메서드는 HTTP 처리 파이프라인의 특정 지점에서 실행됩니다.

  • __init__(self): 서버가 시작된 후 첫 번째 요청 시 한 번만 실행됩니다. 미들웨어 초기화나 활성화 여부를 결정하는 데 사용됩니다.
def __init__(self):
    self.enabled = True
  • process_request(self, request): URL 라우팅 이전에 호출되며, request 객체가 생성된 직후 실행됩니다. 여기서 HttpResponse를 반환하면 이후 단계는 생략되고 바로 응답이 전달됩니다.
def process_request(self, request):
    print(f"요청 수신: {request.path}")
  • process_view(self, request, view_func, view_args, view_kwargs): URL 매칭 후, 실제 뷰 함수가 호출되기 전에 실행됩니다. 이 메서드에서도 응답 객체를 반환하면 뷰는 실행되지 않습니다.
def process_view(self, request, view_func, view_args, view_kwargs):
    print(f"호출될 뷰: {view_func.__name__}")
  • process_response(self, request, response): 뷰에서 응답이 반환된 후, 클라이언트에 전송되기 전에 반드시 호출됩니다. 응답 객체를 수정하거나 로깅 목적으로 사용할 수 있으며, 항상 응답 객체를 반환해야 합니다.
def process_response(self, request, response):
    print("응답 전송 완료")
    return response
  • process_exception(self, request, exception): 뷰에서 예외가 발생했을 때 호출됩니다. 오류 로깅이나 사용자 정의 오류 페이지 처리에 유용합니다. 반환값이 HttpResponse라면 해당 응답이 클라이언트에 전달됩니다.
def process_exception(self, request, exception):
    print(f"예외 발생: {exception}")

커스텀 미들웨어 작성 예제

예를 들어, 요청 처리 시간을 측정하고 로그를 출력하는 미들웨어를 만들어보겠습니다.

  1. 프로젝트 내 임의의 앱 디렉터리 (예: booktest)에 middleware.py 파일을 생성합니다.
import time

class TimingMiddleware:
    def __init__(self, get_response):
        self.get_response = get_response

    def __call__(self, request):
        start_time = time.time()
        
        response = self.get_response(request)
        
        duration = time.time() - start_time
        print(f"요청 처리 소요 시간: {duration:.2f}초")
        
        return response

    def process_view(self, request, view_func, view_args, view_kwargs):
        print(f"[VIEW] {view_func.__module__}.{view_func.__name__} 호출 준비")

    def process_exception(self, request, exception):
        print(f"[ERROR] {type(exception).__name__}: {exception}")
  1. 설정 파일 settings.py의 MIDDLEWARE 리스트에 새 미들웨어를 추가합니다.
MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    # ... 기타 미들웨어
    'booktest.middleware.TimingMiddleware',  # 커스텀 미들웨어 등록
]
  1. 테스트용 뷰를 수정하여 동작 확인:
from django.http import HttpResponse

def index(request):
    print("뷰 함수 실행 중...")
    return HttpResponse("Hello, Middleware!")
  1. 개발 서버를 실행하고 요청을 보내면, 콘솔에 아래와 같은 출력이 나타납니다:
뷰 함수 실행 중...
[VIEW] booktest.views.index 호출 준비
요청 처리 소요 시간: 0.01초

예외 처리 미들웨어의 실행 순서

여러 개의 미들웨어가 process_exception 메서드를 정의하고 있을 경우, 설정 파일의 MIDDLEWARE 리스트에서 더 아래에 위치한 미들웨어부터 먼저 호출됩니다. 즉, 등록 순서의 역순으로 실행됩니다. 따라서 예외 핸들링은 가장 마지막에 등록된 미들웨어가 우선 처리하게 됩니다.

예를 들어, 다음과 같이 두 개의 예외 미들웨어가 등록되어 있다면:

class LogErrorMiddleware:
    def process_exception(self, request, exception):
        print("[Log] 오류 기록됨")

class HandleErrorMiddleware:
    def process_exception(self, request, exception):
        print("[Handle] 오류 처리 시작")
        return HttpResponse("오류가 발생했습니다.", status=500)

실제로는 HandleErrorMiddleware가 먼저 실행되고, 거기서 응답을 반환하면 LogErrorMiddleware는 호출되지 않습니다.

태그: Django 미들웨어 Custom Middleware process_request process_view

9월 30일 02:39에 게시됨