Middlewares
Описание
Middleware
— это промежуточное ПО, позволяющее выполнять определённые действия до и после обработки запроса маршрутом.
from rapidy import Rapidy
from rapidy.http import middleware, get, Request, StreamResponse
from rapidy.typedefs import CallNext
@middleware
async def hello_rapidy_middleware(request: Request, call_next: CallNext) -> StreamResponse:
print('before')
handler_response = await call_next(request)
print('after')
return handler_response
@get('/')
async def handler() -> dict[str, str]:
return {'hello': 'rapidy'}
rapidy = Rapidy(
http_route_handlers=[handler],
middlewares=[hello_rapidy_middleware],
)
Порядок атрибутов
В веб-обработчике первым аргументом всегда передаётся Request
, а вторым — CallNext
(обработчик запроса или middleware
в цепочке).
(Они имеют одинаковую сигнатуру — rapidy.typedefs.CallNext
.)
Тип ответа обработчика
Ответ веб-обработчика или следующего middleware
в цепочке всегда будет StreamResponse
. Учитывайте это при проектировании ваших middleware
.
Способы создания
Создавать middleware
можно двумя способами.
Без параметров
Этот вариант подходит, если вам не нужно управлять запросом внутри middleware
.
С параметрами
Используйте этот способ, если хотите более гибко управлять ответом на запрос.
@middleware(
response_validate=...,
response_type = ...,
response_content_type = ...,
response_charset = ...,
response_zlib_executor = ...,
response_zlib_executor_size = ...,
response_include_fields = ...,
response_exclude_fields = ...,
response_by_alias = ...,
response_exclude_unset = ...,
response_exclude_defaults = ...,
response_exclude_none = ...,
response_custom_encoder = ...,
response_json_encoder = ...,
)
async def hello_middleware(request: Request, call_next: CallNext) -> StreamResponse:
Атрибуты
Rapidy-middleware
поддерживают все механизмы валидации данных, доступные в веб-обработчиках, а также работу с ответами.
Валидация
Как и веб-обработчики, middleware
могут получать доступ к объектам запроса через атрибуты.
Перед тем как продолжить, рекомендуем ознакомиться с разделом Request — Управление HTTP-запросом, поскольку middleware
используют такую же логику обработки параметров запроса.
Обработка Bearer
-токена.
from rapidy.http import middleware, StreamResponse, Header, Request
from rapidy.typedefs import CallNext
TOKEN_REGEXP = '^[Bb]earer (?P<token>[A-Za-z0-9-_=.]*)'
@middleware
async def get_bearer_middleware(
request: Request,
call_next: CallNext,
bearer_token: str = Header(alias='Authorization', pattern=TOKEN_REGEXP),
) -> StreamResponse:
# process token here ...
return await call_next(request)
Если вы извлекаете body
как в middleware
, так и в обработчике, ошибки о повторном чтении данных не возникнет.
Данные кешируются в памяти и повторно используются при валидации.
Управление ответом
Как и веб-обработчики, middleware
могут управлять ответами через собственные атрибуты.
Перед тем как продолжить, рекомендуем ознакомиться с разделом Response — Управление HTTP-ответом, поскольку middleware
используют ту же логику обработки ответов.
Управление ответом возможно только в случае, если middleware
возвращает необработанный тип данных (любой, кроме Response
или StreamResponse
).
Middleware
управляет ответом с помощью атрибутов.
from rapidy import Rapidy
from rapidy.http import middleware, StreamResponse, get, Request
from rapidy.enums import ContentType
from rapidy.typedefs import CallNext
@middleware(response_content_type=ContentType.text_html)
async def hello_rapidy_middleware(request: Request, call_next: CallNext) -> StreamResponse | str:
try:
return await call_next(request)
except Exception:
return 'server error' # Content-Type='text/html'
@get('/')
async def handler() -> dict[str, str]:
raise Exception
rapidy = Rapidy(middlewares=[hello_rapidy_middleware], http_route_handlers=[handler])
Middleware
не может управлять ответом с помощью атрибутов.
from rapidy import Rapidy
from rapidy.http import middleware, StreamResponse, get, Request, Response
from rapidy.enums import ContentType
from rapidy.typedefs import CallNext
@middleware(response_content_type=ContentType.text_html)
async def hello_rapidy_middleware(request: Request, call_next: CallNext) -> StreamResponse:
try:
return await call_next(request)
except Exception:
return Response(status=500) # Content-Type='application/octet-stream'
@get('/')
async def handler() -> dict[str, str]:
raise Exception
rapidy = Rapidy(middlewares=[hello_rapidy_middleware], http_route_handlers=[handler])
Доступ к Response
.
@middleware
async def hello_rapidy_middleware(
request: Request,
call_next: CallNext,
response: Response,
) -> StreamResponse:
Response
создаётся только для текущего middleware
.
Middleware
возвращает другой тип данных
Если middleware
возвращает любой тип данных, кроме StreamResponse
, укажите его в Union
, чтобы Rapidy
использовала этот тип при проверке ответов.