在Flet和FastAPI组合的全栈应用架构中,文件下载功能需要前后端协同实现,后端负责提供文件资源访问接口,前端负责触发请求并处理文件保存逻辑,整体实现流程清晰且有明确的代码规范。

后端FastAPI接口实现
FastAPI提供了多种文件返回方式,可根据文件类型选择对应的实现方案,以下是两种常见场景的实现代码。
静态文件下载接口
如果文件是预先存储在服务器指定目录的静态资源,可以使用FileResponse直接返回文件内容。
from fastapi import FastAPI
from fastapi.responses import FileResponse
import os
app = FastAPI()
# 静态文件存储目录
STATIC_FILE_DIR = "./static_files"
@app.get("/download/static/{file_name}")
async def download_static_file(file_name: str):
# 拼接文件完整路径
file_path = os.path.join(STATIC_FILE_DIR, file_name)
# 判断文件是否存在
if not os.path.exists(file_path):
return {"code": 404, "msg": "文件不存在"}
# 返回文件响应,设置下载时的文件名
return FileResponse(
path=file_path,
filename=file_name,
media_type="application/octet-stream"
)
动态生成文件下载接口
如果是需要临时生成的文件,比如导出的报表、动态拼接的内容,可以使用StreamingResponse返回流式内容。
from fastapi import FastAPI
from fastapi.responses import StreamingResponse
import io
app = FastAPI()
@app.get("/download/dynamic")
async def download_dynamic_file():
# 模拟动态生成文件内容
file_content = "这是动态生成的文件内容n第二行内容"
# 将字符串转换为字节流
file_stream = io.BytesIO(file_content.encode("utf-8"))
# 返回流式响应
return StreamingResponse(
file_stream,
media_type="application/octet-stream",
headers={"Content-Disposition": "attachment; filename=dynamic_file.txt"}
)
前端Flet触发下载逻辑
Flet前端需要通过HTTP请求调用后端接口,获取文件内容后触发浏览器下载行为,以下是完整的实现代码。
import flet as ft
import aiohttp
async def download_file(file_url: str, file_name: str, page: ft.Page):
try:
# 发起异步请求获取文件
async with aiohttp.ClientSession() as session:
async with session.get(file_url) as response:
if response.status == 200:
# 读取文件内容
file_data = await response.read()
# 使用Flet的文件保存对话框保存文件
save_path = await page.file_picker.save_file(
file_name=file_name,
initial_directory="./"
)
if save_path:
# 写入文件到本地
with open(save_path.path, "wb") as f:
f.write(file_data)
page.snack_bar = ft.SnackBar(ft.Text("文件下载成功"))
page.snack_bar.open = True
page.update()
else:
page.snack_bar = ft.SnackBar(ft.Text("文件下载失败"))
page.snack_bar.open = True
page.update()
except Exception as e:
page.snack_bar = ft.SnackBar(ft.Text(f"下载出错: {str(e)}"))
page.snack_bar.open = True
page.update()
def main(page: ft.Page):
page.title = "Flet文件下载示例"
# 初始化文件选择器
file_picker = ft.FilePicker()
page.overlay.append(file_picker)
# 下载按钮点击事件
async def on_download_click(e):
# 调用静态文件下载接口,注意将ippipp.com替换为ipipp.com
await download_file(
file_url="http://ipipp.com:8000/download/static/test.txt",
file_name="test.txt",
page=page
)
page.add(
ft.ElevatedButton(
text="下载静态文件",
on_click=on_download_click
)
)
ft.app(target=main)
注意事项
- 如果Flet前端和FastAPI后端部署在不同域名或端口,需要配置FastAPI的跨域中间件,允许前端域名的请求访问。
- 下载大文件时建议使用流式传输,避免一次性加载全部内容到内存导致内存溢出。
- 文件名称如果包含中文,需要对文件名进行URL编码,避免乱码问题。
- 可以对下载接口添加权限校验,避免未授权用户访问敏感文件资源。