HTTP-заголовки
В этом разделе рассмотрим, как извлекать и проверять заголовки с помощью Rapidy
.
Вы можете проверить данные, используя любой тип, поддерживаемый pydantic
.
Описание
HTTP-заголовки позволяют клиенту и серверу обмениваться дополнительной информацией в HTTP-запросах и ответах.
Извлечение одного заголовка
Header
позволяет получить конкретный заголовок.
from rapidy.http import get, Header
@get('/')
async def handler(
host: str = Header(alias='Host'),
) -> ...:
from rapidy.http import get, Header
@get('/')
async def handler(
host: str = Header(alias='Host'),
keep_alive: str = Header(alias='Keep-Alive'),
) -> ...:
Извлечение всех заголовков
Headers
позволяет извлечь сразу все заголовки.
Извлечение в заранее заданную схему
pydantic.BaseModel
from pydantic import BaseModel, Field
from rapidy.http import get, Headers
class HeadersData(BaseModel):
host: str = Field(alias='Host')
keep_alive: str = Field(alias='Keep-Alive')
@get('/')
async def handler(
headers_data: HeadersData = Headers(),
) -> ...:
dataclasses.dataclass
dataclasses.dataclass
поддерживаются в качестве модели, но задать alias
стандартными средствами dataclasses
невозможно.
from dataclasses import dataclass
from rapidy.http import get, Headers
@dataclass
class HeadersData:
host: str
keep_alive: str # cannot extract if header name is 'Keep-Alive'
@get('/')
async def handler(
headers_data: HeadersData = Headers(),
) -> ...:
# {"errors": [{"type": "missing", "loc": ["header", "keep_alive" ], "msg": "Field required"}]}
Извлечение в словарь
from rapidy.http import get, Headers
@get('/')
async def handler(
headers_data: dict[str, str] = Headers(),
) -> ...:
# {Host': '0.0.0.0:8080', 'Connection': 'keep-alive', 'Upgrade-Insecure-Requests': '1', 'User-Agent': '...'}
Извлечение без валидации
Отключение валидации не рекомендуется.
Если отключить валидацию, параметр вернёт базовую структуру aiohttp
:
Header
→str
Headers
→CIMultiDictProxy[str]
Способы отключения валидации
Явное отключение
from multidict import CIMultiDictProxy
from rapidy.http import get, Header, Headers
@get('/')
async def handler_1(
header_host: str = Header(alias='Host', validate=False)
) -> ...:
# "0.0.0.0:8080"
@get('/')
async def handler_2(
headers_data: CIMultiDictProxy[str] = Headers(validate=False)
) -> ...:
# <CIMultiDictProxy('Host': '0.0.0.0:8080', 'Connection': 'keep-alive', 'Upgrade-Insecure-Requests': '1', 'User-Agent': '...')>
Использование Any
from typing import Any
@get('/')
async def handler_1(
header_host: Any = Header(alias='Host')
) -> ...:
# "0.0.0.0:8080"
@get('/')
async def handler_2(
headers_data: Any = Headers()
) -> ...:
# <CIMultiDictProxy('Host': '0.0.0.0:8080', 'Connection': 'keep-alive', 'Upgrade-Insecure-Requests': '1', 'User-Agent': '...')>
Отсутствие аннотации типа
Если тип не указан, по умолчанию используется Any
.
from typing import Any
@get('/')
async def handler_1(
header_host=Header(alias='Host')
) -> ...:
# "0.0.0.0:8080"
@get('/')
async def handler_2(
headers_data=Headers()
) -> ...:
# <CIMultiDictProxy('Host': '0.0.0.0:8080', 'Connection': 'keep-alive', 'Upgrade-Insecure-Requests': '1', 'User-Agent': '...')>
Значения по умолчанию
Значение по умолчанию для Header
будет использовано, если в запросе отсутствует заголовок с указанным именем.
Значение по умолчанию для Headers
будет использовано, если в запросе нет ни одного заголовка.
Значение по умолчанию для Headers
в реальности не применяется.
Любой HTTP-клиент всегда отправляет базовые заголовки, поэтому этот случай практически невозможен. Однако, если такое вдруг произойдёт, механизм отработает корректно.
Использование default
@get('/')
async def handler(
some_header: str = Header(alias='Some-Header', default='SomeValue'),
) -> ...:
from typing import Annotated
@get('/')
async def handler(
some_header: Annotated[str, Header(alias='Some-Header', default='SomeValue')],
) -> ...:
from typing import Annotated
@get('/')
async def handler(
some_header: Annotated[str, Header(alias='Some-Header')] = 'SomeValue',
) -> ...:
Использование default_factory
@get('/')
async def handler(
some_header: str = Header(alias='Some-Header', default_factory=lambda: 'SomeValue'),
) -> ...:
from typing import Annotated
@get('/')
async def handler(
some_header: Annotated[str, Header(alias='Some-Header', default_factory=lambda:'SomeValue')],
) -> ...:
Нельзя одновременно использовать default
и default_factory
.
При попытке задать оба параметра будет вызвано исключение pydantic
:
Предупреждения и особенности
Использование Header
и Headers
одновременно
Невозможно использовать Header
и Headers
одновременно в одном обработчике.
@get('/')
async def handler(
host: str = Header(alias='Host'),
headers_data: HeadersData = Headers(),
) -> ...:
При запуске приложения будет вызвано исключение AnotherDataExtractionTypeAlreadyExistsError
.
------------------------------
Attribute with this data extraction type cannot be added to the handler - another data extraction type is already use in handler.
Handler path: `main.py`
Handler name: `handler`
Attribute name: `headers_data`
------------------------------
Атрибут alias
в Headers
Атрибут alias
не работает в параметре Headers()
.
@get('/')
async def handler(
headers_data: HeadersData = Headers(alias='SomeName'), # <-- alias not working
) -> ...:
Как извлекаются сырые данные
В Rapidy
используется метод headers
объекта Request
, после чего полученные данные передаются в pydantic
для валидации.
Как происходит извлечение внутри Rapidy
Rapidy
использует встроенные механизмы aiohttp
.
Подробнее об объекте aiohttp.Request
и методах извлечения данных можно узнать
здесь.