前言

在 Web 开发中,表单提交文件上传是最常用的功能:表单用于接收用户输入的文本数据,文件上传用于接收图片、文档等二进制数据。FastAPI 对这两种场景提供了极简、高性能的支持,配合自动文档、异步处理,开发效率极高。推荐使用postman来进行接口测试,文章末尾会提及postman的简单使用操作。

一、基础铺垫:Python 文件操作核心

在学习文件上传前,先回顾 Python 内置文件操作,这是保存上传文件的基础。

1. open() 函数

用于打开/创建文件,是文件操作的核心函数:

# 语法
open(文件路径, 操作模式, encoding="编码格式")
  • 参数1:文件路径(推荐相对路径,../ 表示上级目录)
  • 参数2:操作模式
    • r:只读
    • w:覆盖写入
    • a:追加写入
    • wb:二进制写入(上传文件必用
  • encoding="utf-8":文本编码,二进制文件无需指定

2. 推荐写法:with open()

自动管理文件资源,无需手动关闭,是最佳实践:

# 读取文本文件
with open("data.txt", "r", encoding="utf-8") as f:
    content = f.read()

# 二进制写入(保存上传文件)
with open("test.png", "wb") as f:
    f.write(二进制内容)

3. 文件夹操作(os 模块)

用于创建、判断上传文件的保存目录:

import os
# 判断文件夹是否存在
if not os.path.exists("上传结果"):
    os.mkdir("上传结果")  # 创建文件夹

二、表单提交(Form Data)

表单用于接收纯文本数据(用户名、密码、备注等),是网页最基础的数据交互方式。

1. 环境依赖

表单提交需要安装依赖库:

pip install python-multipart

2. 核心语法

FastAPI 使用 Form(...) 接收表单数据,参数名必须与前端表单 name 属性一致。

3. 实战代码

from fastapi import FastAPI, Form

app = FastAPI()

# 登录表单接口
@app.post("/login")
def login(
    # 定义表单参数,... 表示必填
    username: str = Form(...),
    password: str = Form(...)
):
    # 校验数据
    if username == "admin" and password == "123456":
        return {"msg": "登录成功"}
    return {"msg": "用户名或密码错误"}

4. 前端表单关键配置

<!-- 必须配置:POST 请求 + 表单编码格式 -->
<form action="/login" method="post">
    <input name="username" type="text">
    <input name="password" type="password">
    <button type="submit">登录</button>
</form>

三、重点:文件上传(核心章节)

文件上传是本教程重点,FastAPI 提供两种方式:bytes(小文件)、UploadFile(推荐,大文件/异步)。

核心规则

  1. 请求方式:POST
  2. 请求格式:multipart/form-data
  3. 依赖:python-multipart
  4. 保存文件:必须使用 wb 二进制写入模式

方式1:bytes 类型(小文件专用)

适用于图片、文档等小文件,直接将文件读取为字节数组。

from fastapi import FastAPI, File
from typing import List
import os

app = FastAPI()

# 创建保存目录
if not os.path.exists("上传结果"):
    os.mkdir("上传结果")

# 单文件上传
@app.post("/upload/single/bytes")
async def upload_single(file: bytes = File()):
    # 保存文件
    with open("上传结果/小文件.png", "wb") as f:
        f.write(file)
    return {"文件大小": len(file)}

# 多文件上传
@app.post("/upload/multi/bytes")
async def upload_multi(files: List[bytes] = File()):
    sizes = [len(file) for file in files]
    return {"所有文件大小": sizes}

方式2:UploadFile 类型(推荐)

支持大文件、异步读取、获取文件名/文件类型,生产环境首选。

核心属性

  • file.filename:文件名
  • file.content_type:文件类型
  • file.size:文件大小
  • await file.read():异步读取文件内容

四、实战:单文件 + 多文件上传(完整版)

1. 单文件上传(带目录创建 + 异常处理)

from fastapi import FastAPI, UploadFile, File, APIRouter
import os

router = APIRouter()

# 自动创建保存目录
SAVE_DIR = "../复习/单文件上传结果"
if not os.path.exists(SAVE_DIR):
    os.mkdir(SAVE_DIR)

@router.post('/only/')
async def upload_single_file(file: UploadFile = File(...)):
    # 拼接完整保存路径
    save_path = f"{SAVE_DIR}/{file.filename}"
    # 二进制写入保存文件
    with open(save_path, "wb") as f:
        f.write(await file.read())
    # 返回结果
    return {
        "message": "单文件上传成功",
        "filename": file.filename,
        "size": file.size
    }

2. 多文件上传(遍历保存 + 异常捕获)

支持一次性上传多个文件,遍历处理,增加异常捕获保证接口稳定。

from fastapi import APIRouter, UploadFile, File
from typing import List
import os

router = APIRouter()

# 配置保存目录
MULTI_SAVE_DIR = "../复习/多文件上传结果"
if not os.path.exists(MULTI_SAVE_DIR):
    os.mkdir(MULTI_SAVE_DIR)

@router.post("/many/")
async def upload_multi_files(files: List[UploadFile] = File(...)):
    """
    多文件上传接口
    - files: 接收文件列表
    - File(...) 表示必填
    """
    try:
        # 遍历所有上传文件
        for file in files:
            save_path = f"{MULTI_SAVE_DIR}/{file.filename}"
            # 异步读取 + 写入文件
            with open(save_path, "wb") as f:
                f.write(await file.read())
        return {"message": "多文件上传成功", "数量": len(files)}
    except Exception as e:
        return {"message": "多文件上传失败", "错误信息": str(e)}

五、Postman 测试指南(关键)

1. 单文件上传

  1. 请求方法:POST
  2. 请求地址:/only/
  3. Body → 选择 form-data
  4. Key 填写 file,类型切换为 File
  5. Value 选择本地文件
  6. 发送请求

2. 多文件上传

  1. 同上基础配置
  2. 新增多行,Key 全部填写 files
  3. 每行选择不同文件
  4. 发送请求,后端自动接收为列表

六、核心总结

  1. 表单提交:使用 Form(...),接收纯文本数据,适合登录、注册等场景。
  2. 文件上传
    • 小文件:bytes = File()
    • 大文件/生产:UploadFile = File()(推荐)
  3. 保存文件:必须用 with open(路径, "wb") 二进制写入。
  4. 目录管理:使用 os 模块提前创建保存目录,避免报错。
  5. 异常处理:上传逻辑必须加 try/except,保证接口健壮性。
  6. 请求格式:文件上传必须使用 multipart/form-data
Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐