2023/09/06

aiohttp和fastapi

FastAPI 与 Aiohttp 使用心得

本文主要记录在使用 FastAPI 作为服务端框架,并以 aiohttp 作为异步客户端进行交互时的一些关键点和技巧。

1. FastAPI 请求体 (Request Body)

在 FastAPI 中,参数可以从不同的来源获取:

  • 路径参数 (Path): 嵌入在 URL 路径中,如 /users/{user_id}

  • 查询参数 (Query): 附加在 URL 末尾,如 ?name=Alice&age=30

当参数不适合放在 URL 中时(例如,包含复杂数据结构或敏感信息),我们应该使用请求体来传输数据。

场景示例: 假设我们需要更新一个物品,同时需要传递物品信息 (Item)、用户信息 (User) 以及一个重要性等级 (importance)。ItemUser 是复杂的 Pydantic 模型,importance 是一个简单的整数。

服务端 (FastAPI)

我们可以使用 Body() 来明确指定某个参数应从请求体中获取。

客户端 (aiohttp)

在客户端,我们需要构造一个符合服务端期望的 JSON 结构,并通过 data 参数发送。

2. 关于参数传递的注意事项

发送表单数据 (application/x-www-form-urlencoded)

当服务端需要接收表单数据时(例如,使用 FastAPI 的 Form),aiohttp 客户端可以直接传递一个字典给 data 参数,它会自动进行 URL 编码。

发送 JSON 数据 (application/json)

发送 JSON 数据有两种推荐的方式:

  1. 使用 json 参数 (推荐): aiohttp 会自动将 Python 字典序列化为 JSON 字符串,并设置正确的 Content-Type: application/json 头。

  2. 使用 data 参数: 需要手动将数据序列化为 JSON 字符串,并手动设置 Content-Type 头。

3. 文件处理

流式下载 (Streaming Download)

当处理大文件时,一次性将整个响应加载到内存中(如使用 .read(), .json(), .text())是危险的。aiohttp 提供了流式 API 来解决这个问题。

resp.content 是一个 aiohttp.StreamReader 实例,它允许我们分块读取响应内容。

注意: 一旦开始使用 resp.content 进行流式读取,就不能再调用 .read(), .json().text() 方法。

文件上传 (multipart/form-data)

当表单中包含文件时,Content-Type 必须是 multipart/form-dataaiohttp 提供了 aiohttp.FormData 对象来轻松构建这种类型的请求。

上传小文件

FormData 会自动处理 boundary 的生成和 Content-Type 头的设置。

上传大文件 (流式上传)

对于非常大的文件,为了避免一次性读入内存,可以提供一个异步生成器作为 dataaiofiles 库是实现这一点的绝佳搭档。

0 评论:

发表评论