将 Axum 程序迁移到 Loco
注意:Loco 基于 Axum,它是“包含所有功能的 Axum”,将您的 Axum 代码移至 Loco 非常容易。
我们将研究 realworld-axum-sqlx,它是一个基于 Axum 的应用程序,尝试使用 API、真实数据库和真实世界场景以及诸如配置和日志记录之类的真实世界的可操作性要求来描述一个真实世界的项目。
一点一点地研究 realworld-axum-sqlx
,我们将证明通过将它从 Axum 移至 Loco,大部分代码早已为您编写好,您将获得更佳的最佳实践、更好的开发体验、集成测试、代码生成和更快速的构建应用程序。
您可以使用这种分解方式来理解如何将您自己的基于 Axum 的应用程序也移至 Loco。如有任何问题,请在 discussions 中联系或点击绿色邀请按钮加入我们的 discord。
main
使用 Axum 时,您必须拥有自己的 main
函数,该函数设置应用程序的每个组件,获取路由器、添加中间件、设置上下文,最后终于继续进行,在套接字上设置 listen
。
这是大量的手动工作,容易出错。
在 Loco 中,您可以:
- 在配置中开启/关闭所需的中间件
- 使用
cargo loco start
而完全不需要main
文件 - 在生产中,您会获得一个名为
your_app
的已编译二进制文件,您可以运行它
移至 Loco
- 在 Loco
config/
中设置所需的中间件
server:
middlewares:
limit_payload:
enable: true
body_limit: 5mb
# .. more middleware below ..
- 在 Loco
config/
中设置服务端口
server:
port: 3000
结论
- 无需编写代码,除非您必须这样做,否则您不需要手动编写 main 函数
- 立即可用的最佳实践,您获得了一个适合所有 Loco 应用程序的统一的、共享的最佳实践主文件
- 易于更改,如果要删除/添加中间件来测试某些内容,您只需在配置中切换开关即可,无需重建
Env
realworld axum 代码库使用 dotenv,它需要在 main
中明确加载:
dotenv::dotenv().ok();
并且必须有一个 .env
文件可用、经过维护并已加载:
DATABASE_URL=postgresql://postgres:{password}@localhost/realworld_axum_sqlx
HMAC_KEY={random-string}
RUST_LOG=realworld_axum_sqlx=debug,tower_http=debug
这是一个示例文件,您可以随项目一起获得它,您必须手动复制和编辑它,这往往容易出错。
移至 Loco
Loco:使用您的标准 config/[stage].yaml
配置,并使用 get_env
从环境加载特定值
# config/development.yaml
# Web 服务器配置
server:
# 服务器将侦听的端口。服务器绑定为 0.0.0.0:{PORT}
port: {{% get_env(name="NODE_PORT", default=3000) %}}
此配置是强类型配置,包含最常用的值,例如数据库 URL、记录器级别和筛选等。无需猜测或重复发明轮子。
结论
- 无需编码,移至 Loco 时编写的代码更少
- 减少活动部分,仅在使用 Axum 时,您必须在 env 变量中添加配置,这是您在使用 Loco 时免费获得的内容
数据库
通常情况下,只使用 Axum 的话,你需要自己设置连接、池,并在路由可用性设置中设置这些。这个过程通常需要你在 main.rs
中添加以下代码:
let db = PgPoolOptions::new()
.max_connections(50) // 最高连接数
.connect(&config.database_url) // 连接数据库 URL
.await
.context("无法连接到数据库 URL")?; // 处理错误
然后,你需要手动连接连接
.layer(AddExtensionLayer::new(ApiContext {
config: Arc::new(config), // 配置
db, // 数据库
}))
转移到 Loco
在 Loco 中,你只需在 config/
文件夹中设置连接池的值即可。我们已经预设了最佳的默认值,所以你通常不需要自己设置,但如果你想这么做,代码如下:
database:
enable_logging: false // 是否启用日志记录
connect_timeout: 500 // 连接超时时间,毫秒
idle_timeout: 500 // 空闲超时间,毫秒
min_connections: 1 // 最小连接数
max_connections: 1 // 最大连接数
结论
- 无需编写代码 - Loco 会自动设置数据库连接池的参数,让你的代码更简洁,并且避免了配置错误的风险。
- 更改更便捷 - 在生产环境中,你可能需要在不同的负载下尝试不同的数据库配置。使用 Axum,你必须重新编译和部署你的应用程序。而使用 Loco,你只需修改配置文件并重新启动即可。
日志记录
在你的应用程序中,你通常需要手动添加日志记录代码。你需要选择一个日志记录框架,比如 tracing
或 slog
,并决定是记录日志还是跟踪,以及选择最合适的记录方式。
以下是在 real-world-axum 项目中记录日志的代码示例。在提供服务的代码中:
// 启用日志记录。使用 `RUST_LOG=tower_http=debug`
.layer(TraceLayer::new_for_http()),
在 main
函数中:
// 初始化日志记录器。
env_logger::init();
你还可以根据需要在程序中添加特定的日志记录代码:
log::error!("SQLx error: {:?}", e);
转移到 Loco
在 Loco 中,我们已经为你解决了这些问题,并提供了多层次的日志记录和跟踪功能:
- 框架内部的日志记录。
- 在路由器中配置的日志记录。
- 底层数据库的日志记录和跟踪。
- 所有 Loco 组件(如任务、后台作业等)都使用相同的日志记录机制。
我们选择了 tracing
作为日志记录框架,以便任何 Rust 库都可以统一地输出日志。
我们还创建了智能过滤器,以便默认情况下不会被你不认识的库的日志所轰炸。
你可以在 config/
文件夹中配置你的日志记录器
logger:
enable: true // 是否启用日志记录功能
pretty_backtrace: true // 是否在日志中显示美观的回溯信息
level: debug // 日志记录级别
format: compact // 日志记录格式
结论
- 无需编写代码 - Loco 为你提供了开箱即用的日志记录功能,无需你自己编写任何代码。
- 更快地构建 - Loco 可以帮助你快速地捕获和跟踪错误,从而加快应用程序的开发速度。
- 更改更便捷 - 在生产环境中,你可能需要在不同的负载下尝试不同的日志记录配置。使用 Axum,你必须重新编译和部署你的应用程序。而使用 Loco,你只需修改配置文件并重新启动即可。
路由
将 Axum 路由移到 Loco 中非常简单。Loco 使用的是原生 Axum 路由。
如果你想使用路由列出和信息等功能,你可以使用原生 Loco 路由,它可以转换为 Axum 路由,或者你可以使用你自己的 Axum 路由。
转移到 Loco
如果你希望实现 1:1 的完全复制粘贴体验,只需复制你的 Axum 路由,并将你的路由插入 Loco 的 after_routes()
挂钩中。
async fn after_routes(router: AxumRouter, _ctx: &AppContext) -> Result<AxumRouter> {
// use AxumRouter to mount your routes and return an AxumRouter
}
如果你希望 Loco 了解有关你的路由的元数据信息(这些信息可能在以后派上用场),请按照这种方式在你的每个控制器的 routes()
函数中编写:
// 这是人们使用 Axum 时通常做的事情
pub fn router() -> Router {
Router::new()
.route("/auth/register", post(create_user))
.route("/auth/login", post(login_user))
}
// 这是使用 Loco 时的情况(注意我们使用了 `Routes` 和 `add`)
pub fn routes() -> Routes {
Routes::new()
.add("/auth/register", post(create_user))
.add("/auth/login", post(login_user))
}
结论
- 无需修改的兼容性 - Loco 使用了 Axum 并保持其所有构建模块的完整,这样你只需使用你现有的 Axum 代码,无需付出任何努力。
- 免费的路由元数据 - Axum 路由的一个缺点是无法描述当前配置的路由,这些路由可用于列出或自动生成 OpenAPI 模式。Loco 有一个小的元数据层来支持这一点,如果你使用了
Routes
,你将免费获得它,而所有的签名仍与 Axum 路由兼容。