Files
fastapi/docs/zh/docs/tutorial/request-files.md
2024-11-18 03:25:44 +01:00

173 lines
6.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 请求文件
`File` 用于定义客户端的上传文件。
/// info | 说明
因为上传文件以「表单数据」形式发送。
所以接收上传文件,要预先安装 <a href="https://github.com/Kludex/python-multipart" class="external-link" target="_blank">`python-multipart`</a>。
例如: `pip install python-multipart`
///
## 导入 `File`
`fastapi` 导入 `File``UploadFile`
{* ../../docs_src/request_files/tutorial001.py hl[1] *}
## 定义 `File` 参数
创建文件(`File`)参数的方式与 `Body``Form` 一样:
{* ../../docs_src/request_files/tutorial001.py hl[7] *}
/// info | 说明
`File` 是直接继承自 `Form` 的类。
注意,从 `fastapi` 导入的 `Query``Path``File` 等项,实际上是返回特定类的函数。
///
/// tip | 提示
声明文件体必须使用 `File`否则FastAPI 会把该参数当作查询参数或请求体JSON参数。
///
文件作为「表单数据」上传。
如果把*路径操作函数*参数的类型声明为 `bytes`**FastAPI** 将以 `bytes` 形式读取和接收文件内容。
这种方式把文件的所有内容都存储在内存里,适用于小型文件。
不过,很多情况下,`UploadFile` 更好用。
## 含 `UploadFile` 的文件参数
定义文件参数时使用 `UploadFile`
{* ../../docs_src/request_files/tutorial001.py hl[12] *}
`UploadFile``bytes` 相比有更多优势:
* 使用 `spooled` 文件:
* 存储在内存的文件超出最大上限时FastAPI 会把文件存入磁盘;
* 这种方式更适于处理图像、视频、二进制文件等大型文件,好处是不会占用所有内存;
* 可获取上传文件的元数据;
* 自带 <a href="https://docs.python.org/zh-cn/3/glossary.html#term-file-like-object" class="external-link" target="_blank">file-like</a> `async` 接口;
* 暴露的 Python <a href="https://docs.python.org/zh-cn/3/library/tempfile.html#tempfile.SpooledTemporaryFile" class="external-link" target="_blank">`SpooledTemporaryFile`</a> 对象可直接传递给其他预期「file-like」对象的库。
### `UploadFile`
`UploadFile` 的属性如下:
* `filename`:上传文件名字符串(`str`),例如, `myimage.jpg`
* `content_type`内容类型MIME 类型 / 媒体类型)字符串(`str`),例如,`image/jpeg`
* `file` <a href="https://docs.python.org/zh-cn/3/library/tempfile.html#tempfile.SpooledTemporaryFile" class="external-link" target="_blank">`SpooledTemporaryFile`</a> <a href="https://docs.python.org/zh-cn/3/glossary.html#term-file-like-object" class="external-link" target="_blank">file-like</a> 对象)。其实就是 Python文件可直接传递给其他预期 `file-like` 对象的函数或支持库。
`UploadFile` 支持以下 `async` 方法,(使用内部 `SpooledTemporaryFile`)可调用相应的文件方法。
* `write(data)`:把 `data` `str``bytes`)写入文件;
* `read(size)`:按指定数量的字节或字符(`size` (`int`))读取文件内容;
* `seek(offset)`:移动至文件 `offset` `int`)字节处的位置;
* 例如,`await myfile.seek(0) ` 移动到文件开头;
* 执行 `await myfile.read()` 后,需再次读取已读取内容时,这种方法特别好用;
* `close()`:关闭文件。
因为上述方法都是 `async` 方法要搭配「await」使用。
例如,在 `async` *路径操作函数* 内,要用以下方式读取文件内容:
```Python
contents = await myfile.read()
```
在普通 `def` *路径操作函数* 内,则可以直接访问 `UploadFile.file`,例如:
```Python
contents = myfile.file.read()
```
/// note | `async` 技术细节
使用 `async` 方法时,**FastAPI** 在线程池中执行文件方法,并 `await` 操作完成。
///
/// note | Starlette 技术细节
**FastAPI**`UploadFile` 直接继承自 **Starlette**`UploadFile`,但添加了一些必要功能,使之与 **Pydantic** 及 FastAPI 的其它部件兼容。
///
## 什么是 「表单数据」
与 JSON 不同HTML 表单(`<form></form>`)向服务器发送数据通常使用「特殊」的编码。
**FastAPI** 要确保从正确的位置读取数据,而不是读取 JSON。
/// note | 技术细节
不包含文件时,表单数据一般用 `application/x-www-form-urlencoded`「媒体类型」编码。
但表单包含文件时,编码为 `multipart/form-data`。使用了 `File`**FastAPI** 就知道要从请求体的正确位置获取文件。
编码和表单字段详见 <a href="https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Methods/POST" class="external-link" target="_blank"><abbr title="Mozilla Developer Network">MDN</abbr> Web 文档的 <code>POST </code></a> 小节。
///
/// warning | 警告
可在一个*路径操作*中声明多个 `File``Form` 参数,但不能同时声明要接收 JSON 的 `Body` 字段。因为此时请求体的编码是 `multipart/form-data`,不是 `application/json`
这不是 **FastAPI** 的问题,而是 HTTP 协议的规定。
///
## 可选文件上传
您可以通过使用标准类型注解并将 None 作为默认值的方式将一个文件参数设为可选:
{* ../../docs_src/request_files/tutorial001_02_py310.py hl[7,14] *}
## 带有额外元数据的 `UploadFile`
您也可以将 `File()``UploadFile` 一起使用,例如,设置额外的元数据:
{* ../../docs_src/request_files/tutorial001_03.py hl[13] *}
## 多文件上传
FastAPI 支持同时上传多个文件。
可用同一个「表单字段」发送含多个文件的「表单数据」。
上传多个文件时,要声明含 `bytes``UploadFile` 的列表(`List`
{* ../../docs_src/request_files/tutorial002_py39.py hl[8,13] *}
接收的也是含 `bytes``UploadFile` 的列表(`list`)。
/// note | 技术细节
也可以使用 `from starlette.responses import HTMLResponse`
`fastapi.responses` 其实与 `starlette.responses` 相同,只是为了方便开发者调用。实际上,大多数 **FastAPI** 的响应都直接从 Starlette 调用。
///
### 带有额外元数据的多文件上传
和之前的方式一样, 您可以为 `File()` 设置额外参数, 即使是 `UploadFile`:
{* ../../docs_src/request_files/tutorial003_py39.py hl[16] *}
## 小结
本节介绍了如何用 `File` 把上传文件声明为(表单数据的)输入参数。