litestar请求
本文内容基于《官方文档-请求》的部分进行制作,对其内容大幅进行缩减,使其能适合新手入门,如何想充分学习litestar可以直接查看官方文档
1. 正常请求
from litestar import Litestar, post
@post(path="/")
async def index(data: dict[str, str]) -> dict[str, str]:
return data
app = Litestar(route_handlers=[index])
正常情况下data
为post上来的json
主体
也支持:Msgspec
,Pydantic
,Attrs
from dataclasses import dataclass
from litestar import Litestar, post
@dataclass
class User:
id: int
name: str
@post(path="/")
async def index(data: User) -> User:
return data
app = Litestar(route_handlers=[index])
2. 自定义文档
from dataclasses import dataclass
from typing import Annotated
from litestar import Litestar, post
from litestar.params import Body
@dataclass
class User:
id: int
name: str
@post(path="/")
async def create_user(
data: Annotated[User, Body(title="Create User", description="Create a new user.")],
) -> User:
return data
app = Litestar(route_handlers=[create_user])
3. Content-type
默认情况下,Litestar 将尝试将请求正文解析为 JSON。可以通过body
设置RequestEncodingType
修改
3.1. x-www-form-urlencoded
格式数据
要访问作为 url 编码的表单数据 (即application/x-www-form-urlencoded Content-Type
标头)发送的数据,请使用 Body 并指定 RequestEncodingType.URL_ENCODED
作为media_type
from dataclasses import dataclass
from typing import Annotated
from litestar import Litestar, post
from litestar.enums import RequestEncodingType
from litestar.params import Body
@dataclass
class User:
id: int
name: str
@post(path="/")
async def create_user(
data: Annotated[User, Body(media_type=RequestEncodingType.URL_ENCODED)],
) -> User:
return data
app = Litestar(route_handlers=[create_user])
URL 编码数据本质上不如 JSON 数据通用 - 例如,它无法处理复杂的字典和深度嵌套的数据。它只应用于简单的数据结构。
3.2. multipart
格式数据
Content-Type标头为multipart/form-data
from dataclasses import dataclass
from typing import Annotated
from litestar import Litestar, post
from litestar.datastructures import UploadFile
from litestar.enums import RequestEncodingType
from litestar.params import Body
@dataclass
class User:
id: int
name: str
form_input_name: UploadFile
@post(path="/")
async def create_user(
data: Annotated[User, Body(media_type=RequestEncodingType.MULTI_PART)],
) -> dict[str, str]:
content = await data.form_input_name.read()
filename = data.form_input_name.filename
return {"id": data.id, "name": data.name, "filename": filename, "size": len(content)}
app = Litestar(route_handlers=[create_user])
3.2.1. 文件作为字典
from typing import Annotated
from litestar import Litestar, post
from litestar.datastructures import UploadFile
from litestar.enums import RequestEncodingType
from litestar.params import Body
@post(path="/")
async def handle_file_upload(
data: Annotated[dict[str, UploadFile], Body(media_type=RequestEncodingType.MULTI_PART)],
) -> dict[str, str]:
file_contents = {}
for name, file in data.items():
content = await file.read()
file_contents[file.filename] = len(content)
return file_contents
app = Litestar(route_handlers=[handle_file_upload])
3.2.2. 文件列表
from typing import Any
from typing import Annotated
from litestar import Litestar, post
from litestar.datastructures import UploadFile
from litestar.enums import RequestEncodingType
from litestar.params import Body
@post(path="/")
async def handle_file_upload(
data: Annotated[list[UploadFile], Body(media_type=RequestEncodingType.MULTI_PART)],
) -> dict[str, tuple[str, str, Any]]:
result = {}
for file in data:
content = await file.read()
result[file.filename] = (len(content), file.content_type, file.headers)
return result
app = Litestar(route_handlers=[handle_file_upload])
3.3. MessagePack
格式数据
from typing import Any
from typing import Annotated
from litestar import Litestar, post
from litestar.enums import RequestEncodingType
from litestar.params import Body
@post(path="/", sync_to_thread=False)
def msgpack_handler(
data: Annotated[dict[str, Any], Body(media_type=RequestEncodingType.MESSAGEPACK)],
) -> dict[str, Any]:
# This will try to parse the request body as `MessagePack` regardless of the
# `Content-Type`
return data
app = Litestar(route_handlers=[msgpack_handler])
4. 自定义请求
2.7.0 新版功能
Litestar 支持自定义request_class
实例,可用于进一步配置默认 Request。下面的示例说明了如何为整个应用程序实现自定义请求类。
from litestar import Litestar, Request, get
from litestar.connection.base import empty_receive, empty_send
from litestar.enums import HttpMethod
from litestar.types import Receive, Scope, Send
KITTEN_NAMES_MAP = {
HttpMethod.GET: "Whiskers",
}
class CustomRequest(Request):
"""Enrich request with the kitten name."""
__slots__ = ("kitten_name",)
def __init__(self, scope: Scope, receive: Receive = empty_receive, send: Send = empty_send) -> None:
"""Initialize CustomRequest class."""
super().__init__(scope=scope, receive=receive, send=send)
self.kitten_name = KITTEN_NAMES_MAP.get(scope["method"], "Mittens")
@get(path="/kitten-name", sync_to_thread=False)
def get_kitten_name(request: CustomRequest) -> str:
"""Get kitten name based on the HTTP method."""
return request.kitten_name
app = Litestar(
route_handlers=[get_kitten_name],
request_class=CustomRequest,
debug=True,
)
5. 限制
可以通过 request_max_body_size
参数,默认为 10MB,此限制适用于使用请求的所有方法 body,包括通过路由处理程序中的 body
参数请求它,以及通过手动构建的Request
使用它实例,例如在中间件中。
要为特定处理程序/路由器/控制器禁用此限制,可以将其设置为None
强烈建议不要设置
request_max_body_size=None
,因为它会通过向受影响的终端节点发送任意大的请求正文来使应用程序遭受拒绝服务 (DoS) 攻击。因为 Litestar 必须读取整个正文才能执行某些作,例如解析 JSON,所以它将填满所有可用的内存/交换,直到应用程序/服务器崩溃,如果没有施加外部限制。 通常,仅在应用程序在反向代理(如 NGINX)后面运行的环境中,才建议这样做,因为此时已经设置了大小限制。
由于 request_max_body_size
是按请求处理的,因此不会影响 middlewares 或 ASGI 处理程序,当它们尝试通过原始 ASGI 活动。为了避免这种情况,中间件和 ASGI 处理程序应该构造一个request
实例并使用常规的 stream()
/ body()
或内容适当的方法以安全的方式使用请求正文。
提示:对于定义
Content-Length
标头的请求,如果标头值超过request_max_body_size
Litestar将不会尝试读取请求正文。