Rust+Axum高性能web系列(3)-多种方式读取配置文件
哈喽,大家好呀,我是呼噜噜,我们在项目里一般都是需要读取yaml、json、toml、env
等格式的配置文件或者从环境变量里读取配置,今天我们就来介绍几种常见的方式
读取多种格式的配置文件
我们这里选用 Rust
中读取常用库 config
,它支持多种格式(YAML、JSON、TOML、INI
等),非常灵活强大
- 添加依赖
config = { version = "0.15.11", features = ["yaml"] } # 配置
anyhow = "1.0.98" # 错误处理
- 我们这里新建一个目录
config
,作为一个子模块,不然逻辑全写在main.rs
中太臃肿了
创建一个config/server.rs
文件,用于定义服务器配置结构体,和对应的方法
use serde::Deserialize;
///服务器配置结构体
#[derive(Debug, Deserialize)]
pub struct ServerConfig {
pub port: Option<u16>,//端口
// pub host: String,
// pub log_level: String,
// pub log_file: String,
// pub log_max_size: u64,
// pub log_max_backups: u64,
// pub log_max_age: u64,
// pub log_compress: bool,
// pub log_local_time: bool,
// pub log_utc_time: bool,
// pub log_format: String,
}
impl ServerConfig {
pub fn port(&self) -> u16 {
self.port.unwrap_or(3000)
}
}
- 然后我们编写
config/mod.rs
,先定义应用总配置结构体AppConfig
,用来整合服务器配置、数据库配置等,再通过load
方法,来实现读取配置文件的核心逻辑,我们这里格式选择"yaml"
mod server;
use std::sync::LazyLock;
pub use server::ServerConfig;
use config::{Config, FileFormat};
use serde::Deserialize;
use anyhow::Context;
#[derive(Debug, Deserialize)]
pub struct AppConfig {
pub server: ServerConfig,
}
static CONFIG: LazyLock<AppConfig> =
LazyLock::new(|| AppConfig::load().expect("初始化配置文件失败"));
impl AppConfig {
pub fn load() -> anyhow::Result<Self> {
Config::builder()
//加载默认配置文件 (必须存在)
.add_source(
config::File::with_name("application")
.format(FileFormat::Yaml)
.required(true)
)
//加载环境变量
.add_source(
config::Environment::with_prefix("APP")
.try_parsing(true)
.separator("_") // 变量前缀分隔符
.list_separator(",") // 嵌套字段分隔符
)
.build()
.with_context(|| anyhow::anyhow!("Failed to load config"))?
.try_deserialize() // 反序列化为AppConfig结构
.with_context(|| anyhow::anyhow!("Failed to deserialize config"))
}
pub fn server(&self) -> &ServerConfig {
&self.server
}
}
pub fn get() -> &'static AppConfig {
&CONFIG
}
这里主要通过Config::builder()
来构建配置加载器,加载yaml配置文件,加载环境变量等等。注意加载多个配置,优先级是后加载者覆盖前者
至于多环境配置文件读取,像java中spirng框架一样,我们可以引入
// 获取当前运行环境,默认为development
let env = std::env::var("APP_ENV").unwrap_or_else(|_| "dev".into());
tracing::info!("APP_ENV:{}", env);
...
// 加载环境特定配置文件 (可选)
.add_source(config::File::with_name(&format!("application-{}", env)).format(FileFormat::Yaml).required(false))
另外static CONFIG: LazyLock<AppConfig> = LazyLock::new(|| AppConfig::load().expect("初始化配置文件失败"));
这行代码是定义并初始化一个全局静态配置对象,它在第一次被访问时(懒加载LazyLock),会尝试自动加载配置文件并初始化,如果失败则直接 panic
并输出提示。这样就能在程序的任何地方,方便地访问全局配置,而且只会加载一次,线程安全。
这里也可以axun状态共享
来实现,但是需要给每个 Handler
进行显式传递,比起全局静态变量要复杂一些。配置这一块我们的原则是,读配置文件,如果没有就取默认配置
- 测试,我们在
main.rs
调用
当然我们得首先创建 src/application.yaml
配置文件
server:
port: 9999
use axum::{
routing::get,
debug_handler,
Json, Router
};
use serde_json::{Value, json};
mod logger;
mod config;//别忘了声明模块!
#[tokio::main]
async fn main() {
let _guard = logger::init();
let app = Router::new()
.route("/testConfig", get(handle_config_test));//配置文件测试
let port = config::get().server().port();
let listener = tokio::net::TcpListener::bind(format!("0.0.0.0:{port}")).await.unwrap();
axum::serve(listener, app).await.unwrap();
}
#[debug_handler]
async fn handle_config_test() -> Json<Value> {
//读取yaml配置文件
let config = config::get();
tracing::info!("server port:{}", config.server().port());
Json(json!({
"code": 0,
"msg": "请求成功",
"data": null
}))
}
请求"/testConfig"这个接口,控制台会打打印
2025-06-26T02:35:17.445796Z INFO server port:9999
at src\main.rs:28 on tokio-runtime-worker ThreadId(10)
需要注意,笔者发现 Rust
打包的可执行文件里,并不会包含配置文件,所以配置文件后续得传到生产环境,建议跟可执行文件同级
如果使用多环境配置文件
读取,那你应该执行下面的命令,将环境变量注入进去
APP_ENV=prod cargo run
这个时候,就有人问博主,为啥我这里报这个错:
博主:我还没说完,上面的是 Linux
下的写法,Windows
下应该这样写:
$env:APP_ENV="prod";cargo run
读取Cargo.toml文件
另外除了上面这些格式的文件,我们要是想读取项目中自带的Cargo.toml
配置,该怎么办?不需要引入新的第三方库,我们可以直接:
use std::env;
...
//读取项目默认Cargo.toml
let name = env!("CARGO_PKG_NAME");
let version = env!("CARGO_PKG_VERSION");
let author = env!("CARGO_PKG_AUTHORS");
tracing::info!("project info:{} {} {}", name, version, author);
日志打印结果:
2025-06-26T02:39:44.920518Z INFO project info:rust_litchi_admin 0.1.0 zhangjunhttps://xiaoniuhululu.com
at src\main.rs:35 on tokio-runtime-worker ThreadId(17)
读取.env文件
常见的配置文件还有.env
格式的,我们这里使用dotenv
来实现我们的需求
- 添加依赖
dotenv = "0.15.0" # 读取.env 文件
- 在根目录下,创建.env文件
BOOK="四大名著"
- 使用测试
在main
函数中,需要检查一下
use dotenv::dotenv;
use std::env;
#[tokio::main]
async fn main() {
...
dotenv().ok();//再访问.env文件前,需要检查是否正常,防止恐慌
axum::serve(listener, app).await.unwrap();
}
- 测试
//读取.env
let book = env::var("BOOK").expect("DATABASE_URL 没有在 .env 文件里设置");
tracing::info!(" book: {}",book);
控制台打印的结果:
2025-06-26T05:33:46.091872Z INFO book: 四大名著
at src\main.rs:40 on tokio-runtime-worker ThreadId(13)
尾语
本文通过 config
和 dotenv
来读取多种格式的配置文件,并与 axum
框架无缝衔接,同时扩展了多环境支持,我们接下来会继续探索 rust 在web领域的应用
参考文章:https://docs.rs/config/0.15.11
作者:小牛呼噜噜
本文到这里就结束啦,感谢阅读,关注同名公众号:小牛呼噜噜,防失联+获取更多技术干货