본문 바로가기

Back-end & Server/Django

[Django] 미들웨어(Middleware)

728x90
반응형

Middleware란?

Django의 요청/응답 처리를 위한 프레임워크

  • Django의 입출력을 전역으로 변경하기 위한 가볍고, 낮은 수준의 플러그인 시스템

 

각 구성 요소는 특정 기능을 담당함.(ex. 사용자가 세션을 사용해 요청과 연결하는 AuthenticationMiddleware)

Django는 기본적으로 제공되는 미들웨어가 포함되어 있고 즉시 사용할 수 있음

 

 

미들웨어 활성화

미들웨어를 활성화 하려면 Django 설정의 MIDDLEWARE_CLASSES 목록에 미들웨어를 추가하면됨

각 미들웨어 구성 요소는 문자열로 표현

 

Hook 및 응용 프로그램 주문

Django는 요청 단계에서 뷰를 호출하기 전에 MIDDLEWARE_CLASSES정의된 순서로 미들웨어를 적용

요청 단계에서 사용할 수 있는 HOOK

  • process_request()
  • process_view()

 

응답 단계에서 뷰를 호출한 후 미들웨어가 아래에서 위로(역순) 적용

응답 단계에서 사용할 수 있는 HOOK

  • process_exception()
  • process_template_response()
  • process_response()

미들웨어 등록 시 가장 중요한 것은 미들웨어를 등록하는 순서임

  • http request 들어올 때 위에서 아래로 미들웨어 적용
  • http response 나갈 때 아래서부터 위로 미들웨어 적용

 

process_request(request)

  • request : HttpRequest 객체임
  • Django가 어떤 뷰를 실행할지 결정하기 전에 각 요청에 대해 호출됨
  • None을 반환하면, Django는 다른 process_request() 미들웨어를 실행한 후, process_view() 미들웨어를 실행하고 마지막으로 적절한 뷰를 실행해 이 요청을 계속 처리
  • HttpResponse 객체를 반환하면, Django는 다른 요청, 뷰 또는 예외 미들웨어 또는 적절한 뷰를 호출하지 않음, 해당 HttpResponse에 응답 미들웨어를 적용하고 결과를 반환함

 

 

process_view(request, view_func, view_args, view_kwargs)

  • request : HttpRequest 객체임
  • view_func : Django가 사용하려는 Python 함수
  • view_args : 뷰에 전달될 위치 인수 목록, request를 포함하지 않음
  • view_kwargs : 뷰에 전달될 키워드 인수 사전, request를 포함하지 않음
  • Django가 view를 호출하기 바로 전에 호출됨
  • None을 반환하면, Django는 이 요청을 처리하고, 다른 process_view() 미들웨어를 실행한 후 적절한 뷰를 실행함
  • HttpResponse 객체를 반환하면, Django는 다른 뷰 또는 예외 미들웨어 또는 적절한 뷰를 호출하지 않음, 해당 HttpResponse에 응답 미들웨어를 적용하고 결과 반환
  • csrf_exempt() csrf_protect() 데커레이터를 제공, CsrfViewMiddleware 클래스는 예외로 간주될 수 있음(view에서 CSRF 유효성 검사를 수행해야 하는 시점을 명시적으로 제어할 수 있도록 해줌)

 

 

process_exception(request, exception)

  • request : HttpRequest 객체임
  • exception : view 함수에서 발생한 예외 object
  • Django는 뷰가 예외를 발생 시킬 때 이 메서드를 호출
  • None을 반환하면, 기본 예외 처리가 시작됨
  • HttpResponse 객체를 반환하면, 템플릿 응답 및 응답 미들웨어가 적용되고 결과 응답이 웹 브라우저에 반환됨
  • 미들웨어는 응답 단계에서 역순으로 실행됨, 예외 미들웨어가 응답을 반환하면 해당 미들웨어 위의 미들웨어 클래스는 전혀 호출되지 않음

 

 

process_template_response(request, response)

  • request : HttpRequest 객체임
  • response : Django 뷰 또는 미들웨어에서 반환된 TemplateResponse object(동등한 object)
  • response 인스턴스TemplateResponse 또는 이와 동등한 것을 나타내는 render() 메서드를 가지고 있다면, 뷰가 실행을 마친 직후에 호출됨
  • render() 메서드를 구현하는 응답 객체를 반환해야 함
  • response.template_nameresponse.context_data변경주어진 응답을 변경할 수 있거나 새로운 TemplateResponse이나 이와 동등한 것을 작성해 반환할 수 있음
  • 명시적으로 응답을 렌더링할 필요 없음(모든 템플릿 응답 미들웨어가 호출되면 응답이 자동으로 렌더링)
  • 응답 단계에서 역순으로 실행됨

 

 

process_response(request, response)

  • request : HttpRequest 객체임
  • response : Django 뷰 또는 미들웨어에서 반환된 HttpResponse 또는 StreamingHttpResponse 객체임
  • 웹 브라우저가 반환되기 전에 모든 응답에 대해 호출됨
  • HttpResponse 또는 StreamingHttpResponse 객체를 반환해야 하고 주어진 응답을 변경하거나 새로운 HttpResponse 또는 StreamingHttpResponse를 생성하고 반환할 수 있음
  • 응답 단계에서 역순으로 실행됨

 

스트리밍 응답 다루기

StreamingHttpResponse에는 content 특성이 없음

콘텐츠에 대한 액세스가 필요한 경우, 스트리밍 응답을 테스트하고 그에 따라 행동을 조정해야함

if response.streaming:
    response.streaming_content = wrap_streaming_content(response.streaming_content)
else :
    response.content = alter_content(response.content)

streaming_content는 너무 커서 메모리에 저장할 수 없다고 가정해야함, 응답 미들웨어는 새로운 생성기에서 이를 생성할 수 있지만, 메모리 소비를 하면 안됨

그래서 wrap_streaming_content는 다음과 같이 구현됨

def wrap_streaming_content(content):
    for chunk in content:
        yield alter_content(chunk)
# yield는 결과의 시퀀스를 반환하기 때문에, 결과를 순회하여 응용할 때 사용
# 스트리밍은 결과를 연쇄적으로 반환하는 과정이기 때문에 yield 사용

 

 

나만의 미들웨어 작성하기

미들웨어는 뷰와 마찬가지로 요청을 받고 응답을 반환하는 callable(호출 가능한 인스턴스, 함수, 메서드 등)

미들웨어는 Python 경로 어디서나 존재할 수 있음

 

함수형태의 작성

def simple_middleware(get_response):
    # One-time configuration and initialization.

    def middleware(request):
        # Code to be executed for each request before
        # the view (and later middleware) are called.

        response = get_response(request)

        # Code to be executed for each request/response after
        # the view is called.

        return response

    return middleware

 

클래스 형태의 작성

class SimpleMiddleware:
    def __init__(self, get_response):
        self.get_response = get_response
        # One-time configuration and initialization.

    def __call__(self, request):
        # Code to be executed for each request before
        # the view (and later middleware) are called.

        response = self.get_response(request)

        # Code to be executed for each request/response after
        # the view is called.

        return response

 

__init__(get_response)

대부분의 미들웨어 클래스는 미들웨어 클래스가 기본적으로 process_* 메서드의 자리표시자 이기 때문에 initializer가 필요하지 않음

어떤 전역 상태가 필요한 경우 __init__을 사용해 설정 가능

주의 사항

  • Django는 파라미터 없이 미들웨어를 초기화하므로 __init__를 인수가 필요하다고 정의할 수 없음
  • __init__gets는 요청당 한 번 호출되는 process_* 메서드와 달리 웹 서버가 첫 번째 요청에 응답할 때 한번만 호출

 

미들웨어를 미사용으로 표시

  • __init__ 메서드는 django.core.exceptions.MiddlewareNotUsed를 발생 시킬 수 있음
  • 이 경우 Django는 프로세스에서 해당 미들웨어 일부를 제거하고, DEBUG가 True로 설정된 경우 디버그 메시지는 django.request logger에 기록

 

비동기 지원

 

Django

The web framework for perfectionists with deadlines.

docs.djangoproject.com

 

사용가능한 미들웨어

 

Django

The web framework for perfectionists with deadlines.

docs.djangoproject.com

 

728x90
반응형

'Back-end & Server > Django' 카테고리의 다른 글

[Django] DB서버 연결  (0) 2023.02.06
[Django] 보안  (0) 2023.02.06
[Django] 캐시 프레임워크  (0) 2023.02.04
[Django] 비 HTML 콘텐츠와 세션  (0) 2023.02.01
[Django] 배포  (0) 2023.01.31