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

Промежуточное ПО - это структура перехватчиков для обработки запросов / ответов 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-адреса и применении шаблона -response и исключительное ПО промежуточного слоя .

Промежуточное ПО может поддерживать только синхронный 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в объект try/exceptи обработке исключения, которое могло быть вызвано более поздним промежуточным программным обеспечением или представлением. Даже если следующее промежуточное ПО в цепочке вызывает Http404исключение, например, ваше промежуточное ПО не увидит этого исключения; вместо этого он получит HttpResponse объект с status_code404.

Вы можете установить, DEBUG_PROPAGATE_EXCEPTIONSчтобы Trueпропустить это преобразование и распространять исключения вверх.

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

Новое в Django 3.1.

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

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

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

Если ваше промежуточное ПО имеет оба и , то Django передаст ему запрос без его преобразования. В этом случае вы можете определить, будет ли ваше промежуточное ПО получать асинхронные запросы, проверив, является ли переданный вам объект функцией сопрограммы, используя .sync_capable = Trueasync_capable = Trueget_responseasyncio.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 ErrorHttp404MIDDLEWARE
Изменено в Django 3.1:

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

Copyright ©2021 All rights reserved