作为动态网站托管应用
介绍
Flet 实现了 FastAPI 应用程序来将您的应用程序运行为动态网站。
默认情况下,它使用 Uvicorn 网络服务器来运行应用程序,但也可以使用任何兼容 ASGI 的服务器。
同步和异步处理程序
在 Flet web 应用中,您可以在同一个应用中混合使用同步和异步方法。
例如,您可以编写如下应用:
import flet as ft
import time
import asyncio
def main(page: ft.Page):
def handler(e):
time.sleep(3)
page.add(ft.Text("Handler clicked"))
async def handler_async(e):
await asyncio.sleep(3)
page.add(ft.Text("Async handler clicked"))
page.add(
ft.ElevatedButton("Call handler", on_click=handler),
ft.ElevatedButton("Call async handler", on_click=handler_async)
)
ft.app(main)
在这个示例中,点击一个按钮由“阻塞”处理程序处理,而点击另一个按钮调用异步处理程序。第一 个处理程序在 threading.Thread
中运行,而第二个处理程序作为 asyncio.Task
运行。
在 web 应用中,使用线程是应用扩展性的一个考虑因素,因为线程是有限资源。通常使用线程池,但随着用户数量的增加,它可能成为瓶颈。
无论如何,如果您的应用主要进行 I/O 操作(数据库、web API)并且/或者您能够使用支持异步的库,我们建议实现异步处理程序。
查看 FastAPI 关于 async/await 的文章以更好地了解并发性和并行性的区别。
本地运行应用
使用 --web
(-w
) 选项启动 Flet 应用作为 web 应用:
flet run --web app.py
将打开一个新的浏览器窗口/标签页,应用将使用随机 TCP 端口。
要在固定端口上运行,请使用 --port
(-p
) 选项:
flet run --web --port 8000 app.py
在生产环境中运行应用
您可以直接使用 python
命令运行程序:
python app.py
默认情况下使用 Uvicorn 网络服务器托管 web 应用。
如果 Flet 检测到应用在无头 Linux 环境(如 Docker 容器或 EC2 VM)中运行:
- 使用端口
8000
运行应用。 - 不会打开带有应用的浏览器窗口。
如果由于某种原因 Flet 无法检测到无头环境,您可以通过定义以下环境变量强制这种行为:
FLET_FORCE_WEB_SERVER=true
ASGI 网络服务器
您可以使用任何兼容 ASGI 的服务器托管您的 Flet web 应用,如默认使用的 Uvicorn、Hypercorn 或 Daphne。
只需告诉 Flet 导出 ASGI 应用:
import flet as ft
def main(page: ft.Page):
page.add(ft.Text("Hello ASGI!"))
app = ft.app(main, export_asgi_app=True)
Hypercorn
Hypercorn 是另一个受 Gunicorn 启发的 ASGI 网络服务器。
使用 Hypercorn 运行应用:
hypercorn main:app --bind 0.0.0.0:8000
Daphne
Daphne 是一个用于 ASGI 和 ASGI-HTTP 的 HTTP、HTTP2 和 WebSocket 协议服务器,开发用于支持 Django Channels。
使用 Daphne 运行应用:
daphne -b 0.0.0.0 -p 8000 main:app
Gunicorn
Gunicorn 是运行 Python web 应用的流行网络服务器。虽然它实现了 WSGI 规范,但可以使用 Uvicorn 提供的工作进程类运行 ASGI FastAPI 应用:
gunicorn --bind 0.0.0.0:8000 -k uvicorn.workers.UvicornWorker counter:app
资源
当您在浏览器中打开 Flet 应用时,它的 index.html
、Flutter 引擎、favicon、图片和其他 web 应用资源由网络服务器提供。这些资源与 flet
Python 包一起打包。然而,有时您需要修改某些文件的内容以自定义应用的外观或行为,例如:
- Favicon。
- 应用加载动画。
- 带有 PWA 详细信息的
manifest.json
。
您可以在 flet.app()
调用中指定 assets_dir
以设置应用可用的资源位置。assets_dir
应该是相对于 main.py
目录的相对路径或绝对路径。assets_dir
参数的默认值是 assets
。
例如,考虑以下程序结构:
/assets
/images/my-image.png
main.py
您可以在应用中按如下方式访问您的图片:
import flet as ft
def main(page: ft.Page):
page.add(ft.Image(src=f"/images/my-image.png"))
ft.app(main, assets_dir="assets")
自定义 web 应用
Favicon
要使用您自己的 favicon 覆盖默认的,将 favicon.png
文件放入资源目录的根目录。它应该是至少 32x32 像素的 PNG 图像。
加载动画
要用您的应用标志覆盖 Flet 动画图像,将 icons/loading-animation.png
图像放入资源目录的根目录。
PWA
渐进式 web 应用(PWA)提供了一种将类应用网站变成类网站应用的方法。
查看 PWAs Turn Websites Into Apps: Here's How 了解 PWA 的介绍。
支持 PWA 的浏览器(安装说明):
- 所有平台上的 Chrome
- 所有平台上的 Edge
- Android 上的 Firefox
- iOS 和 iPadOS 上的 Safari
本节信息基于以下资源(查看更多详细信息):
Manifest
您可以在 manifest.json
中更改 PWA 的名称、描述、颜色和其他信息,必须将其放在 assets
目录的根目录。
以下是您可能希望自定义的最常见 manifest 项目的链接:
name
- 通常显示给用户的 web 应用名称。short_name
- 如果没有足够空间显示name
,则显示给用户的 web 应用名称。description
- 解释应用程序的功能。theme_color
- 定义应用程序的默认主题颜色。background_color
- 定义在应用程序页面加载样式表之前显示的占位符背景颜色。
图标
自定义图标应放置在 assets/icons
目录中:
icon-192.png
、icon-512.png
- 显示在 Windows 任务栏中的应用图标。icon-maskable-192.png
、icon-maskable-512.png
- 显示在 Android 中的应用图标。apple-touch-icon-192.png
- 显示在 iOS 中的应用图标。
环境变量
网络应用托管的每个方面都可以通过环境变量进行额外控制:
FLET_FORCE_WEB_SERVER
-true
强制将应用程序作为 web 应用运行。在无头 Linux 主机上自动设置。FLET_SERVER_PORT
- 运行应用程序的 TCP 端口。如果程序在 Linux 服务器上运行或设置了FLET_FORCE_WEB_SERVER
,则为8000
;否则为随机端口。FLET_SERVER_IP
- 监听 web 应用的 IP 地址,例如127.0.0.1
。默认值为0.0.0.0
- 绑定到所有服务器 IP。FLET_ASSETS_DIR
- 应用程序“assets”目录的绝对路径。FLET_UPLOAD_DIR
- 应用程序“upload”目录的绝对
路径。
FLET_MAX_UPLOAD_SIZE
- 允许上传文件的最大大小(以字节为单位)。如果未指定,则为无限制。FLET_SECRET_KEY
- 签署临时上传 URL 的密钥。FLET_WEB_APP_PATH
- 主机 web 应用的域名后的 URL 路径,例如/apps/myapp
。默认值为/
- 在根目录中托管应用。FLET_SESSION_TIMEOUT
- 会话生命周期,以秒为单位。默认值为3600
。FLET_OAUTH_STATE_TIMEOUT
- 完成 OAuth web 流程的最大允许时间,以秒为单位。默认值为600
。FLET_WEB_RENDERER
- Flutter 渲染模式:canvaskit
(默认)、html
或auto
。FLET_WEB_USE_COLOR_EMOJI
-true
、True
或1
加载带有彩色表情符号的网络字体。FLET_WEB_ROUTE_URL_STRATEGY
-path
(默认)或hash
。FLET_WEBSOCKET_HANDLER_ENDPOINT
- WebSocket 处理程序的自定义路径。默认值为/ws
。FLET_UPLOAD_HANDLER_ENDPOINT
- 上传处理程序的自定义路径。默认值为/upload
。FLET_OAUTH_CALLBACK_HANDLER_ENDPOINT
- OAuth 处理程序的自定义路径。默认值为/oauth_callback
。
高级 FastAPI 场景
Flet FastAPI 应用
flet.fastapi.app()
函数创建一个新的 FastAPI 应用程序来处理带有 session_handler
的会话,并在应用程序的根目录下挂载以下端点:
/ws
(WS) - Flet 应用的 WebSocket 处理程序。当建立新的 WebSocket 连接并创建新应用会话时,它会调用 main()
函数。
/upload
(PUT) - 文件上传处理程序。
/oauth_callback
(GET) - OAuth 流程回调处理程序。
/
(GET) - 带有 SPA catch-all 处理程序的 Flet 应用静态文件。
flet.fastapi.app()
参数:
session_handler
(函数或协程)- 应用程序入口点 - 为新连接的用户调用的方法。处理程序必须有一个参数:page
-Page
实例。assets_dir
(str,可选)- 应用程序资源目录的绝对路径。app_name
(str,可选)- PWA 应用名称。app_short_name
(str,可选)- PWA 应用短名称。app_description
(str,可选)- PWA 应用描述。web_renderer
(WebRenderer)- 默认为WebRenderer.CANVAS_KIT
的 web 渲染器。use_color_emoji
(bool)- 是否加载带有彩色表情符号的字体。默认值为False
。route_url_strategy
(str)- 路由 URL 策略:path
(默认)或hash
。upload_dir
(str)- 上传文件目录的绝对路径。max_upload_size
(str, int)- 单个上传的最大大小(以字节为单位)。如果为None
则为无限制。secret_key
(str,可选)- 签署和验证上传请求的密钥。session_timeout_seconds
(int,可选)- 用户断开连接后的会话生命周期(以秒为单位)。oauth_state_timeout_seconds
(int,可选)- OAuth 状态生命周期(以秒为单位),这是从开始 OAuth 流程到重定向到 OAuth 回调 URL 的最大允许时间。
在同一域名下托管多个 Flet 应用
import flet as ft
import flet.fastapi as flet_fastapi
async def root_main(page: ft.Page):
await page.add_async(ft.Text("This is root app!"))
async def sub_main(page: ft.Page):
await page.add_async(ft.Text("This is sub app!"))
app = flet_fastapi.FastAPI()
app.mount("/sub-app", flet_fastapi.app(sub_main))
app.mount("/", flet_fastapi.app(root_main))
子应用必须在根 Flet 应用之前映射,因为它为 SPA 配置了 catch-all index.html
。
使用 uvicorn
运行应用并访问 http://127.0.0.1:8000 和 http://127.0.0.1:8000/sub-app/ 以查看两个 Flet 应用正在运行。
注意 /sub-app/
URL 中的斜杠 - 没有斜杠的请求将路由到根应用。
将 Flet 添加到现有的 FastAPI 应用
from contextlib import asynccontextmanager
import flet as ft
import flet.fastapi as flet_fastapi
from fastapi import FastAPI
@asynccontextmanager
async def lifespan(app: FastAPI):
await flet_fastapi.app_manager.start()
yield
await flet_fastapi.app_manager.shutdown()
app = FastAPI(lifespan=lifespan)
async def main(page: ft.Page):
await page.add_async(ft.Text("Hello, Flet!"))
app.mount("/flet-app", flet_fastapi.app(main))
将 Flet 应用添加到现有的 FastAPI 应用时,您需要在应用启动时调用 flet_fastapi.app_manager.start()
,在关闭时调用 flet_fastapi.app_manager.shutdown()
。使用最适合您的方式:生命周期(在上面的示例中)或应用事件。
app_manager.start()
方法启动清理过期会话和 OAuth 流程状态的后台任务。
app_manager.shutdown()
方法删除 Flet 应用创建的任何临时文件。
配置单个 Flet 端点
静态文件
一个 FastAPI 应用来提供静态 Flet 应用文件(index.html、manifest.json、Flutter JS 应用等)和用户资源。
from flet.fastapi import FastAPI, FletStaticFiles
app = FastAPI()
# 挂载到 web 应用的根目录
app.mount(path="/", app=FletStaticFiles())
FletStaticFiles
构造函数的参数:
app_mount_path
(str)- Flet 应用的绝对 URL。默认值为/
。assets_dir
(str,可选)- 应用程序资源目录的绝对路径。app_name
(str,可选)- PWA 应用名称。app_short_name
(str,可选)- PWA 应用短名称。app_description
(str,可选)- PWA 应用描述。web_renderer
(WebRenderer)- 默认为WebRenderer.CANVAS_KIT
的 web 渲染器。use_color_emoji
(bool)- 是否加载带有彩色表情符号的字体。默认值为False
。route_url_strategy
(str)- 路由 URL 策略:path
(默认)或hash
。websocket_endpoint_path
(str,可选)- Flet 应用 WebSocket 处理程序的绝对 URL。默认值为{app_mount_path}/ws
。
WebSocket 处理程序
处理来自浏览器中运行的 Flet 客户端应用的 WebSocket 连接。WebSocket 通道用于将事件从浏览器发送到 Flet 后端代码并接收页面实时增量更新。
from flet.fastapi import FletApp
async def main(page: ft.Page):
await page.add_async(ft.Text("Hello, Flet!"))
@app.websocket("/app1/ws")
async def flet_app(websocket: WebSocket):
await FletApp(main).handle(websocket)
session_handler
(协程)- 应用程序入口点 - 为新连接的用户调用的异步方法。处理程序协程必须有一个参数:page
-Page
实例。session_timeout_seconds
(int,可选)- 用户断开连接后的会话生命周期(以秒为单位)。oauth_state_timeout_seconds
(int,可选)- OAuth 状态生命周期(以秒为单位),这是从开始 OAuth 流程到重定向到 OAuth 回调 URL 的最大允许时间。upload_endpoint_path
(str,可选)- 上传端点的绝对 URL,例如/upload
。secret_key
(str,可选)- 签署上传请求的密钥。
上传处理程序
处理 FilePicker 控件的文件上传。此端点是可选的 - 如果您的应用不使用 FilePicker,则不需要它。
from flet.fastapi import FletUpload
@app.put("/upload")
async def flet_uploads(request: Request):
await FletUpload("/Users/feodor/Downloads/123").handle(request)
OAuth 回调处理程序
处理 OAuth 流程回调请求。如果您的应用不使用[身份验证
](/docs/cookbook/authentication),则不需要此端点。
from flet.fastapi import FletOAuth
@app.get("/oauth_callback")
async def flet_oauth(request: Request):
return await FletOAuth().handle(request)