Posted on:
Last modified:
FastAPI 中默认的数据格式是 JSON,但是有时还是需要使用传统的 Web 表单,比如上传文件。让我们 来简单看下吧。
from fastapi import Form
@app.post("/login")
async def login(username: str=Form(...), password: str=Form(...)):
auth(username, password)
return username
其中参数的名字要和 html 中 input 标签的 name 对应上。
如果要在 HTML 页面中上传文件,那么文件只能通过表单的形式进行传送。在 FastAPI 中,使用 File 对象来表示一个文件。
from fastapi import File, UploadFile
# 这里的 file 是 bytes 类型,会直接进内存,适合临时文件
@app.route("/files")
def create_file(file: bytes = File(...)):
...
# 注意 file 的类型区别,这种方式会混存到硬盘,还可以读取文件名等更多属性
@app.route("/files2")
def create_file2(file: UploadFile = File(...)):
...
其中参数的名字也要和 <input type="file" name="xxx">
中的名字对应上。
如果文件类型声明为 bytes,那么文件会直接缓存到内存中,可以直接用 io.BytesIO
打开读取。
如果文件类型定义为 UploadFile
类型,那么当文件过大的时候 FastAPI 会在硬盘中缓存文件。
使用 bytes 当然方便,但是如果每个用户都在上传 2G 大小的文件,可能你的内存一会儿就爆了。
特别注意, FastAPI 0.44.1 引入了一个 bug,导致使用 bytes 参数必须得放到第一个位置才行。
不过使用 UploadFile
则没有影响。
UploadFile
的属性和方法有:
file.filename # 用户上传的原始文件名,注意一定要做过滤,不能相信任何用户数据
file.content_type # 文件类型,比如 image/jpeg
file.file: SpooledTemporaryFile # 真正打开的文件对象
def get_valid_filename(s):
"""过滤文件名的一个方法,来自 django"""
s = str(s).strip().replace(' ', '_')
return re.sub(r'(?u)[^-\w.]', '', s)
# 一些异步读写方法
await file.write(data)
await file.read(size)
await file.seek(offset)
await file.close()
# 如果是在一个同步的 handler 中,可以直接使用对应的 file 属性的方法,不需要 await
data = file.file.read()
如果你使用的不是 async 函数的话,可以使用 UploadFile.file
属性对应的方法访问,
SpooledTemporaryFile
是标准库中的一个类型。
Form 和 File 可以一起使用,因为他们都使用相同的编码方式一起发送给服务器,但是不能和 Body 或者 BaseModel 共用,因为编码方式不兼容。一个是 form,一个是 json.
也可以单独发送二进制文件,但是需要从 Body 中手动读取,而且文件名等信息也需要额外读取。
© 2016-2022 Yifei Kong. Powered by ynotes
All contents are under the CC-BY-NC-SA license, if not otherwise specified.
Opinions expressed here are solely my own and do not express the views or opinions of my employer.
友情链接: MySQL 教程站