Промежуточное ПО

Промежуточное ПО - это структура перехватчиков для обработки запросов / ответов Django. Это легкая, низкоуровневая система «плагинов» для глобального изменения ввода или вывода Django.

Каждый компонент промежуточного программного обеспечения отвечает за выполнение определенной функции. Например, Django включает компонент промежуточного программного обеспечения AuthenticationMiddleware , который связывает пользователей с запросами с помощью сеансов.

В этом документе объясняется, как работает промежуточное ПО, как вы активируете промежуточное ПО и как писать собственное промежуточное ПО. Django поставляется с некоторым встроенным промежуточным программным обеспечением, которое вы можете использовать прямо из коробки. Они задокументированы во встроенном справочнике по промежуточному программному обеспечению .

Написание собственного промежуточного программного обеспечения

Фабрика промежуточного программного обеспечения - это вызываемый объект, который принимает get_response вызываемый объект и возвращает промежуточное программное обеспечение. Промежуточное ПО - это вызываемый объект, который принимает запрос и возвращает ответ, как и представление.

Промежуточное ПО можно записать как функцию, которая выглядит следующим образом:

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

get_response Вызываемый при условии Джанго может быть фактическим вид (если это последний в списке промежуточного слоя) , или он может быть следующим промежуточным слоем в цепи. Текущее промежуточное программное обеспечение не должно знать или заботиться о том, что именно оно представляет, просто оно представляет все, что будет дальше.

Вышеупомянутое является небольшим упрощением - get_response вызываемый для последнего промежуточного программного обеспечения в цепочке будет не фактическим представлением, а скорее методом-оболочкой из обработчика, который заботится о применении промежуточного программного обеспечения представления , вызове представления с соответствующими аргументами URL-адреса и применении шаблона промежуточное ПО для ответов и исключений .

Промежуточное ПО может поддерживать только синхронный Python (по умолчанию), только асинхронный Python или и то, и другое. См. Раздел « Асинхронная поддержка», чтобы узнать, как рекламировать то, что вы поддерживаете, и узнать, какой тип запроса вы получаете.

Промежуточное ПО может находиться где угодно на вашем пути Python.

__init__(get_response)

Фабрики промежуточного программного обеспечения должны принимать get_response аргумент. Вы также можете инициализировать какое-то глобальное состояние для промежуточного программного обеспечения. Имейте в виду пару предостережений:

  • Django инициализирует ваше промежуточное ПО только с get_response аргументом, поэтому вы не можете определить, __init__() что он требует каких-либо других аргументов.
  • В отличие от __call__() метода, который вызывается один раз за запрос, он __init__() вызывается только один раз при запуске веб-сервера.

Пометка промежуточного ПО как неиспользуемого

Иногда во время запуска полезно определить, следует ли использовать промежуточное программное обеспечение. В этих случаях __init__() метод вашего промежуточного программного обеспечения может поднять MiddlewareNotUsed . Затем Django удалит это промежуточное программное обеспечение из процесса промежуточного программного обеспечения и записывает отладочное сообщение в журнал django.request, когда он DEBUG есть True .

Активация промежуточного ПО

Чтобы активировать компонент промежуточного программного обеспечения, добавьте его в MIDDLEWARE список в настройках Django.

В MIDDLEWARE каждый компонент промежуточного программного обеспечения представлен строкой: полный путь Python к классу или имени функции фабрики промежуточного программного обеспечения. Например, вот значение по умолчанию, созданное :django-admin startproject

MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

Установка Django не требует промежуточного программного обеспечения - MIDDLEWARE может быть пустым, если хотите, - но настоятельно рекомендуется, чтобы вы хотя бы использовали CommonMiddleware .

Порядок MIDDLEWARE имеет значение, потому что промежуточное программное обеспечение может зависеть от другого промежуточного программного обеспечения. Например, AuthenticationMiddleware сохраняет аутентифицированного пользователя в сеансе; следовательно, он должен работать после SessionMiddleware . См. Раздел Упорядочивание промежуточного программного обеспечения для некоторых общих советов по упорядочиванию классов промежуточного программного обеспечения Django.

Порядок и наслоение промежуточного программного обеспечения

На этапе запроса, перед вызовом представления, Django применяет промежуточное ПО в том порядке, в котором оно определено MIDDLEWARE , сверху вниз.

Вы можете думать об этом как о луковице: каждый класс промежуточного программного обеспечения - это «слой», который обертывает представление, которое находится в ядре лука. Если запрос проходит через все уровни луковицы (каждый из них вызывает get_response передачу запроса на следующий уровень), вплоть до представления в ядре, ответ затем пройдет через каждый уровень (в обратном порядке) на путь обратно.

Если один из слоев решает выполнить короткое замыкание и вернуть ответ, даже не вызывая его get_response , ни один из слоев лука внутри этого слоя (включая представление) не увидит запрос или ответ. Ответ будет возвращен только через те же уровни, через которые прошел запрос.

Другие хуки промежуточного ПО

Помимо базового шаблона промежуточного программного обеспечения запроса / ответа, описанного ранее, вы можете добавить три других специальных метода в промежуточное программное обеспечение на основе классов:

process_view()

process_view( запрос , view_func , view_args , view_kwargs )

request это HttpRequest объект. view_func - это функция Python, которую Django собирается использовать. (Это фактический объект функции, а не имя функции в виде строки.) view_args - это список позиционных аргументов, которые будут переданы в представление, и view_kwargs словарь аргументов ключевых слов, которые будут переданы в представление. Ни view_args ни view_kwargs включить, ни включить первый аргумент представления ( request ).

process_view() вызывается непосредственно перед тем, как Django вызывает представление.

Он должен возвращать либо None или HttpResponse объект. Если он вернется None , Django продолжит обработку этого запроса, выполняя любое другое process_view() промежуточное ПО, а затем соответствующее представление. Если он возвращает HttpResponse объект, Django не станет вызывать соответствующее представление; он применит к нему промежуточное ПО ответа HttpResponse и вернет результат.

Заметка

Доступ к request.POST внутреннему промежуточному программному обеспечению перед process_view() запуском представления или внутри будет препятствовать тому, чтобы какое-либо представление, запущенное после промежуточного программного обеспечения, могло изменить обработчики загрузки для запроса , и обычно этого следует избегать.

CsrfViewMiddleware Класс можно рассматривать как исключение, так как она обеспечивает csrf_exempt() и csrf_protect() декораторов , которые позволяют вид явно контролировать , в какой момент проверки CSRF должно произойти.

process_exception()

process_exception( запрос , исключение )

request это HttpRequest объект. exception это Exception объект, созданный функцией просмотра.

Django вызывает, process_exception() когда представление вызывает исключение. process_exception() должен возвращать либо None или HttpResponse объект. Если он возвращает HttpResponse объект, будет применен ответ шаблона и промежуточное программное обеспечение ответа, и полученный ответ будет возвращен браузеру. В противном случае включается обработка исключений по умолчанию .

Опять же, промежуточное ПО запускается в обратном порядке на этапе ответа, который включает process_exception . Если промежуточное программное обеспечение исключения возвращает ответ, process_exception методы классов промежуточного программного обеспечения выше этого промежуточного программного обеспечения не будут вызваны вообще.

process_template_response()

process_template_response( запрос , ответ )

request это HttpRequest объект. response - TemplateResponse объект (или эквивалент), возвращаемый представлением Django или промежуточным программным обеспечением.

process_template_response() вызывается сразу после завершения выполнения представления, если у экземпляра ответа есть render() метод, указывающий, что это метод TemplateResponse или эквивалент.

Он должен возвращать объект ответа, реализующий render метод. Он может изменить данное response , изменив response.template_name и response.context_data , или он может создать и вернуть совершенно новый TemplateResponse или эквивалентный.

Вам не нужно явно отображать ответы - ответы будут отображаться автоматически после вызова всего промежуточного программного обеспечения ответа шаблона.

Промежуточное ПО запускается в обратном порядке на этапе ответа, который включает process_template_response() .

Работа с потоковыми ответами

В отличие от HttpResponse , StreamingHttpResponse не имеет content атрибута. В результате промежуточное ПО больше не может предполагать, что все ответы будут иметь content атрибут. Если им нужен доступ к контенту, они должны протестировать потоковые ответы и соответствующим образом скорректировать свое поведение:

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

Заметка

streaming_content следует считать, что он слишком велик для хранения в памяти. ПО промежуточного слоя ответа может обернуть его в новый генератор, но не должно его использовать. Упаковка обычно реализуется следующим образом:

def wrap_streaming_content(content):
    for chunk in content:
        yield alter_content(chunk)

Обработка исключений

Django автоматически преобразует исключения, вызванные представлением или промежуточным программным обеспечением, в соответствующий HTTP-ответ с кодом состояния ошибки. Некоторые исключения преобразуются в коды состояния 4xx, в то время как неизвестное исключение преобразуется в код состояния 500.

Это преобразование происходит до и после каждого промежуточного программного обеспечения (вы можете думать о нем как о тонкой пленке между каждым слоем луковицы), так что каждое промежуточное программное обеспечение всегда может рассчитывать на получение какого-либо ответа HTTP от вызова его get_response вызываемого. Промежуточному программному обеспечению не нужно беспокоиться о переносе своего вызова get_response в a try/except и обработке исключения, которое могло быть вызвано более поздним промежуточным программным обеспечением или представлением. Даже если следующее промежуточное ПО в цепочке Http404 вызовет исключение, например, ваше промежуточное ПО не увидит этого исключения; вместо этого он получит HttpResponse объект с status_code 404.

Асинхронная поддержка

Новое в Django 3.1.

Промежуточное ПО может поддерживать любую комбинацию синхронных и асинхронных запросов. Django адаптирует запросы в соответствии с требованиями промежуточного программного обеспечения, если оно не может поддерживать оба, но со снижением производительности.

По умолчанию Django предполагает, что ваше промежуточное ПО способно обрабатывать только синхронные запросы. Чтобы изменить эти предположения, установите следующие атрибуты в функции или классе фабрики промежуточного программного обеспечения:

  • sync_capable - логическое значение, указывающее, может ли промежуточное ПО обрабатывать синхронные запросы. По умолчанию True .
  • async_capable - логическое значение, указывающее, может ли промежуточное ПО обрабатывать асинхронные запросы. По умолчанию False .

Если в вашем промежуточном программном обеспечении есть оба и , то Django передаст ему запрос без его преобразования. В этом случае вы можете определить, будет ли ваше промежуточное ПО получать асинхронные запросы, проверив, является ли переданный вам объект функцией сопрограммы, используя .sync_capable = True async_capable = True get_response asyncio.iscoroutinefunction()

django.utils.decorators Модуль содержит sync_only_middleware() , async_only_middleware() и sync_and_async_middleware() декоратор , которые позволяют применять эти флаги промежуточных уровня заводских функций.

Возвращаемый вызываемый объект должен соответствовать синхронному или асинхронному характеру get_response метода. Если у вас асинхронный get_response , вы должны вернуть функцию сопрограммы ( ).async def

process_view , process_template_response и process_exception методы, если они предусмотрены, также должны быть адаптированы для соответствия режиму синхронизации / асинхронности. Однако Django индивидуально адаптирует их по мере необходимости, если вы этого не сделаете, что приведет к дополнительному снижению производительности.

Вот пример того, как создать функцию промежуточного программного обеспечения, которая поддерживает оба:

import asyncio
from django.utils.decorators import sync_and_async_middleware

@sync_and_async_middleware
def simple_middleware(get_response):
    # One-time configuration and initialization goes here.
    if asyncio.iscoroutinefunction(get_response):
        async def middleware(request):
            # Do something here!
            response = await get_response(request)
            return response

    else:
        def middleware(request):
            # Do something here!
            response = get_response(request)
            return response

    return middleware

Заметка

Если вы объявляете гибридное промежуточное ПО, которое поддерживает как синхронные, так и асинхронные вызовы, тип получаемого вызова может не соответствовать базовому представлению. Django оптимизирует стек вызовов промежуточного программного обеспечения, чтобы иметь как можно меньше переходов синхронизация / асинхронность.

Таким образом, даже если вы обертываете асинхронное представление, вас могут вызвать в режиме синхронизации, если между вами и представлением есть другое синхронное промежуточное ПО.

Обновление промежуточного ПО в стиле до Django 1.10

класс django.utils.deprecation.MiddlewareMixin

Django django.utils.deprecation.MiddlewareMixin упрощает создание классов промежуточного программного обеспечения, совместимых как MIDDLEWARE со старыми MIDDLEWARE_CLASSES , так и со старыми , и поддерживает синхронные и асинхронные запросы. Все классы промежуточного программного обеспечения, включенные в Django, совместимы с обеими настройками.

Миксин предоставляет __init__() метод, который требует get_response аргумента и сохраняет его в self.get_response .

__call__() Метод:

  1. Звонки self.process_request(request) (если определены).
  2. Вызывает, self.get_response(request) чтобы получить ответ от более позднего промежуточного программного обеспечения и представления.
  3. Звонки (если определены).self.process_response(request, response)
  4. Возвращает ответ.

Если используется с MIDDLEWARE_CLASSES , __call__() метод никогда не будет использоваться; Django звонит process_request() и process_response() напрямую.

В большинстве случаев наследования от этого миксина будет достаточно, чтобы сделать промежуточное ПО старого стиля совместимым с новой системой с достаточной обратной совместимостью. Новая семантика короткого замыкания будет безвредной или даже полезной для существующего промежуточного программного обеспечения. В некоторых случаях класс промежуточного программного обеспечения может нуждаться в некоторых изменениях, чтобы приспособиться к новой семантике.

Это поведенческие различия между использованием MIDDLEWARE и MIDDLEWARE_CLASSES :

  1. В соответствии с этим у MIDDLEWARE_CLASSES каждого промежуточного программного обеспечения всегда будет process_response вызываться его метод, даже если более раннее промежуточное программное обеспечение завершило работу, вернув ответ от своего process_request метода. В MIDDLEWARE нижней части промежуточное ПО ведет себя больше как луковица: уровни, через которые проходит ответ на выходе, являются теми же уровнями, которые видели запрос на входе. Если промежуточное ПО выполняет короткое замыкание, только это промежуточное ПО и те, которые были перед ним, MIDDLEWARE будут увидеть ответ.
  2. Под MIDDLEWARE_CLASSES , process_exception применяются для исключения поднятого из промежуточного программного process_request метода. Под MIDDLEWARE , process_exception применяется только к исключениям, вызванным из представления (или из render метода a TemplateResponse ). Исключения, вызванные промежуточным программным обеспечением, преобразуются в соответствующий HTTP-ответ и затем передаются следующему промежуточному программному обеспечению.
  3. Ниже MIDDLEWARE_CLASSES , если process_response метод вызывает исключение, process_response методы всего более раннего промежуточного программного обеспечения пропускаются и всегда возвращается ответ HTTP (даже если возникшее исключение было, например, ошибкой ). Ниже исключение, вызванное промежуточным программным обеспечением, будет немедленно преобразовано в соответствующий HTTP-ответ, а затем следующее промежуточное программное обеспечение в строке увидит этот ответ. Промежуточное ПО никогда не пропускается из-за того, что промежуточное ПО вызывает исключение.500 Internal Server Error Http404 MIDDLEWARE
Изменено в Django 3.1:

Добавлена ​​поддержка асинхронных запросов в MiddlewareMixin .

Copyright ©2020 All rights reserved