diff --git a/crates/erp-server/config/default.toml b/crates/erp-server/config/default.toml index 8f03249..c704243 100644 --- a/crates/erp-server/config/default.toml +++ b/crates/erp-server/config/default.toml @@ -54,6 +54,6 @@ upload_dir = "./uploads" max_file_size = "10MB" [rate_limit] -# Redis 不可达时是否拒绝请求。生产环境必须设置为 true。 -# 可通过 ERP__RATE_LIMIT__FAIL_CLOSE=true 环境变量覆盖。 -fail_close = false +# Redis 不可达时是否拒绝请求(fail-close)。默认 true = 安全优先。 +# 开发环境可设为 false 以避免 Redis 依赖:ERP__RATE_LIMIT__FAIL_CLOSE=false +fail_close = true diff --git a/crates/erp-server/src/config.rs b/crates/erp-server/src/config.rs index e30ec28..c2035fd 100644 --- a/crates/erp-server/src/config.rs +++ b/crates/erp-server/src/config.rs @@ -127,14 +127,18 @@ impl StorageConfig { #[derive(Debug, Clone, Deserialize)] pub struct RateLimitConfig { - /// Redis 不可达时是否拒绝请求(生产环境必须为 true)。 - #[serde(default)] + /// Redis 不可达时是否拒绝请求。默认 true(安全优先)。 + #[serde(default = "default_fail_close")] pub fail_close: bool, } +fn default_fail_close() -> bool { + true +} + impl Default for RateLimitConfig { fn default() -> Self { - Self { fail_close: false } + Self { fail_close: true } } } @@ -154,3 +158,20 @@ impl AppConfig { Ok(app_config) } } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn rate_limit_default_is_fail_close() { + let config = RateLimitConfig::default(); + assert!(config.fail_close, "RateLimitConfig 默认应为 fail_close = true"); + } + + #[test] + fn serde_default_uses_custom_fn() { + let config: RateLimitConfig = serde_json::from_str("{}").unwrap(); + assert!(config.fail_close, "serde 反序列化缺失字段时应使用 default_fail_close() = true"); + } +}