Параметры тела запроса
В то время как параметры пути, запроса и заголовков обычно представляют собой небольшие фрагменты данных, закодированные в URL или заголовках, параметры тела запроса несут основную полезную нагрузку запроса. Они обычно используются в методах как POST, PUT и PATCH, где клиенту необходимо отправить структурированные данные на сервер.
Например:
Это типичный HTTP-запрос с JSON-телом:
POST /users HTTP/1.1
Content-Type: application/json
{
"username": "alice",
"age": 30
}
Параметры тела запроса vs другие параметры запроса
При обработке HTTP-запросов важно понимать разницу между параметрами тела запроса и другими параметрами запроса, такими как параметры запроса, параметры пути и значения заголовков. Эти различия влияют на то, как данные отправляются клиентом и как они разбираются сервером.
-
Расположение в запросе Параметры тела запроса передаются фундаментально другим способом по сравнению с другими параметрами.
Давайте еще раз рассмотрим типичный пример POST-запроса:
POST /submit HTTP/1.1
Host: example.com
Content-Type: application/json
Content-Length: 27
{"key": "value"}Этот HTTP-запрос разделен на две части, разделенные пустой строкой:
-
Строка запроса и заголовки (все до пустой строки): это включает метод (POST), путь (/submit) и заголовки, такие как Content-Type.
-
Тело запроса (все после пустой строки): это содержит фактическую полезную нагрузку, в данном случае JSON-объект.
В отличие от параметров запроса или пути, параметры тела запроса не появляются в URL или в заголовках. Они размещаются в теле запроса и обычно используются для отправки структурированных данных, таких как JSON, XML или значения, закодированные формой.
-
-
Формат кодирования Еще одно ключевое отличие заключается в том, как кодируются параметры тела запроса:
При отправке параметров запроса кодирование происходит в URL:
GET /search?query=python&sort=asc
Значения запроса кодируются URL и относительно ограничены по размеру.
-
Параметры тела запроса, с другой стороны, кодируются на основе заголовка
Content-Type
. Общие форматы включают:-
application/json — для отправки JSON-полезных нагрузок.
-
application/x-www-form-urlencoded — часто используется при отправке HTML-форм.
-
multipart/form-data — используется при загрузке файлов.
-
Сервер использует заголовок
Content-Type
, чтобы решить, как разобрать тело запроса. Например, если заголовок application/json, сервер ожидает, что тело будет содержать действительный JSON. -
Сводка различий
Особенность | Параметры Query/Path/Header | Параметры Body |
---|---|---|
Появляется в URL? | Да | Нет |
Местоположение в запросе | Строка запроса или заголовки | После пустой строки (тело запроса) |
Тип кодирования | URL-кодированный (запрос), обычный текст | JSON, данные формы, multipart и т.д. |
Случай использования | Малые/простые значения, маршрутизация | Сложные объекты, формы, загрузка файлов |
Понимание этого различия важно при проектировании или использовании API, особенно в типизированных фреймворках, таких как lihil, где параметры тела запроса и другие параметры объявляются по-разному и разбираются с различной логикой под капотом.
Объявление параметра тела запроса в lihil
В lihil есть два способа объявить тело запроса:
Неявное объявление тела запроса через структурированный тип данных
Вы можете просто определить модель тела, используя msgspec.Struct, и lihil автоматически будет рассматривать ее как тело запроса:
import msgspec
from lihil import Route
class CreateUser(msgspec.Struct):
username: str
age: int
user = Route("/users")
@user.post
async def create_user(data: CreateUser) -> str:
return f"Hello {data.username}!"
Это предпочтительный способ, когда тело вашего запроса является структурированным объектом (например, JSON-документом).
начиная с lihil 0.2.9
, структурированные типы данных:
msgspec.Struct
dataclasses.dataclass
typing.Typeddict
dict
поддерживаются для параметра тела запроса
Явно с Param("body")
Если вы хотите быть явным, или если вы комбинируете данные тела с другими типами параметров, вы можете использовать Param("body"):
from lihil import Param
from typing import Annotated
@user.post
async def create_user(
data: Annotated[CreateUser, Param("body")]
) -> str:
return f"Hello {data.username}!"
Этот подход особенно полезен, когда ваше тело является примитивным значением, таким как строка или список.
Ограничения и валидация
Поскольку параметры тела запроса используют msgspec, вы можете применять ограничения валидации непосредственно в вашем Struct или через Param, точно так же, как вы делали бы с параметрами пути или запроса:
from lihil import Param
from typing import Annotated
class CreateUser(msgspec.Struct):
username: Annotated[str, Param(min_length=3, max_length=30)]
age: Annotated[int, Param(ge=0, le=120)]
Пользовательские декодеры
Для продвинутых случаев использования вы можете предоставить пользовательский декодер через Param:
from lihil import Param
from typing import Annotated
def parse_data(value: bytes) -> CreateUser:
# ваша пользовательская логика
return CreateUser(...)
@user.post
async def create_user(
data: Annotated[CreateUser, Param("body", decoder=parse_data)]
): ...
Это дает вам полный контроль над тем, как интерпретируются сырые байты тела.
Резюме
-
Параметры тела запроса - это мощный способ отправки структурированных данных в HTTP-запросах.
-
Они необходимы для API, которые должны принимать сложные типы данных, такие как JSON-объекты или бинарные файлы.
-
Lihil упрощает работу с параметрами тела запроса, позволяя вам определять их с помощью структурированных типов данных или
Param("body")
. -
Вы также можете применять ограничения валидации и даже использовать пользовательские декодеры для продвинутых сценариев.