从 Flask 迁移¶
ASGI 与 WSGI¶
Flask 是一个 WSGI 框架,而 Litestar 是使用现代 ASGI 标准构建的。一个关键区别是 ASGI 是为异步而构建的。
虽然 Flask 增加了对 async/await 的支持,但其核心仍然是同步的;Flask 中的异步支持仅限于单个端点。这意味着虽然您可以在 Flask 中使用 async def 定义端点,但它们不会并发运行 - 请求仍将一次处理一个。Flask 通过为每个请求创建一个事件循环来处理异步端点,在其中运行端点函数,然后返回其结果。
另一方面,ASGI 则完全相反;它在一个中央事件循环中运行所有内容。然后,Litestar 通过在非阻塞方式下 在事件循环上 运行同步函数来增加对同步函数的支持。这意味着同步和异步代码都可以并发运行。
路由¶
from flask import Flask
app = Flask(__name__)
@app.route("/")
def index():
return "Index Page"
@app.route("/hello")
def hello():
return "Hello, World"
from litestar import Litestar, get
@get("/")
def index() -> str:
return "Index Page"
@get("/hello")
def hello() -> str:
return "Hello, World"
app = Litestar([index, hello])
路径参数¶
from flask import Flask
app = Flask(__name__)
@app.route("/user/<username>")
def show_user_profile(username):
return f"User {username}"
@app.route("/post/<int:post_id>")
def show_post(post_id):
return f"Post {post_id}"
@app.route("/path/<path:subpath>")
def show_subpath(subpath):
return f"Subpath {subpath}"
from litestar import Litestar, get
from pathlib import Path
@get("/user/{username:str}")
def show_user_profile(username: str) -> str:
return f"User {username}"
@get("/post/{post_id:int}")
def show_post(post_id: int) -> str:
return f"Post {post_id}"
@get("/path/{subpath:path}")
def show_subpath(subpath: Path) -> str:
return f"Subpath {subpath}"
app = Litestar([show_user_profile, show_post, show_subpath])
请求对象¶
在 Flask 中,当前请求可以通过全局 request 变量访问。在 Litestar 中,可以通过处理器函数中的可选参数访问请求。
from flask import Flask, request
app = Flask(__name__)
@app.get("/")
def index():
print(request.method)
from litestar import Litestar, get, Request
@get("/")
def index(request: Request) -> None:
print(request.method)
请求方法¶
Flask |
Litestar |
|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
使用 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
静态文件¶
与 Flask 一样,Litestar 也具有提供静态文件的功能,但虽然 Flask 会自动从 static 文件夹提供文件,但在 Litestar 中必须显式配置。
from litestar import Litestar
from litestar.static_files import create_static_files_router
app = Litestar(route_handlers=[
create_static_files_router(path="/static", directories=["assets"]),
])
模板¶
Flask 内置了 Jinja 模板引擎。您也可以在 Litestar 中使用 Jinja,但需要显式安装它。您可以通过使用 pip install 'litestar[jinja]' 安装 Litestar 来完成。除了 Jinja,Litestar 还支持 Mako 和 Minijinja 模板。
from flask import Flask, render_template
app = Flask(__name__)
@app.route("/hello/<name>")
def hello(name):
return render_template("hello.html", name=name)
from litestar import Litestar, get
from litestar.contrib.jinja import JinjaTemplateEngine
from litestar.response import Template
from litestar.template.config import TemplateConfig
@get("/hello/{name:str}")
def hello(name: str) -> Template:
return Template(response_name="hello.html", context={"name": name})
app = Litestar(
[hello],
template_config=TemplateConfig(directory="templates", engine=JinjaTemplateEngine),
)
重定向¶
对于重定向,使用 Redirect 而不是 redirect:
from flask import Flask, redirect, url_for
app = Flask(__name__)
@app.get("/")
def index():
return "hello"
@app.get("/hello")
def hello():
return redirect(url_for("index"))
from litestar import Litestar, get
from litestar.response import Redirect
@get("/")
def index() -> str:
return "hello"
@get("/hello")
def hello() -> Redirect:
return Redirect(path="/")
app = Litestar([index, hello])
引发 HTTP 错误¶
使用 HTTPException 而不是 abort 函数:
from flask import Flask, abort
app = Flask(__name__)
@app.get("/")
def index():
abort(400, "this did not work")
from litestar import Litestar, get
from litestar.exceptions import HTTPException
@get("/")
def index() -> None:
raise HTTPException(status_code=400, detail="this did not work")
app = Litestar([index])
设置状态码¶
from flask import Flask
app = Flask(__name__)
@app.get("/")
def index():
return "not found", 404
from litestar import Litestar, get, Response
@get("/static", status_code=404)
def static_status() -> str:
return "not found"
@get("/dynamic")
def dynamic_status() -> Response[str]:
return Response("not found", status_code=404)
app = Litestar([static_status, dynamic_status])
序列化¶
Flask 使用显式转换(如 jsonify)和推断(即返回数据的类型)的混合来确定数据应如何序列化。相反,Litestar 假设返回的数据旨在序列化为 JSON,并将这样做,除非另有说明。
from flask import Flask, Response
app = Flask(__name__)
@app.get("/json")
def get_json():
return {"hello": "world"}
@app.get("/text")
def get_text():
return "hello, world!"
@app.get("/html")
def get_html():
return Response("<strong>hello, world</strong>", mimetype="text/html")
from litestar import Litestar, get, MediaType
@get("/json")
def get_json() -> dict[str, str]:
return {"hello": "world"}
@get("/text", media_type=MediaType.TEXT)
def get_text() -> str:
return "hello, world"
@get("/html", media_type=MediaType.HTML)
def get_html() -> str:
return "<strong>hello, world</strong>"
app = Litestar([get_json, get_text, get_html])
错误处理¶
from flask import Flask
from werkzeug.exceptions import HTTPException
app = Flask(__name__)
@app.errorhandler(HTTPException)
def handle_exception(e): ...
from litestar import Litestar, Request, Response
from litestar.exceptions import HTTPException
def handle_exception(request: Request, exception: Exception) -> Response: ...
app = Litestar([], exception_handlers={HTTPException: handle_exception})
参见
要了解有关异常处理的更多信息,请查看文档中的此章节:
usage/exceptions:exception handling