From facb75d6325e4af489fefa7c9de9b4f25d8dd39c Mon Sep 17 00:00:00 2001 From: xfy Date: Wed, 17 Jun 2026 16:38:41 +0800 Subject: [PATCH] feat: make HTTP compression algorithms configurable via COMPRESSION_ALGORITHMS --- .env.example | 5 +++++ src/main.rs | 62 ++++++++++++++++++++++++++++++++++++++++++++-------- 2 files changed, 58 insertions(+), 9 deletions(-) diff --git a/.env.example b/.env.example index e2489a7..2cb1cb9 100644 --- a/.env.example +++ b/.env.example @@ -26,6 +26,11 @@ DB_POOL_SIZE=20 # SSR page cache duration in seconds (default: 3600) SSR_CACHE_SECS=3600 +# Compression algorithms for HTTP responses. +# Comma-separated list, case-insensitive. Supported: gzip, brotli (or br), deflate, zstd. +# Leave empty or unset to disable compression entirely. +COMPRESSION_ALGORITHMS=gzip,brotli,deflate,zstd + # Image serving cache headers (hardcoded defaults) # Uploaded image assets are served with Cache-Control: public, max-age=31536000, immutable. # Processed variants (?w=, ?format=, etc.) are cached for 24 hours. diff --git a/src/main.rs b/src/main.rs index 2999c51..da7ffa3 100644 --- a/src/main.rs +++ b/src/main.rs @@ -28,6 +28,48 @@ mod theme; mod utils; mod webp; +/// 根据 COMPRESSION_ALGORITHMS 环境变量构造 CompressionLayer。 +/// 环境变量为空或未设置时返回 None,表示不启用压缩。 +#[cfg(feature = "server")] +fn compression_layer_from_env() -> Option { + use tower_http::compression::CompressionLayer; + + let env = std::env::var("COMPRESSION_ALGORITHMS").unwrap_or_default(); + let env = env.trim(); + if env.is_empty() { + return None; + } + + let mut gzip = false; + let mut brotli = false; + let mut deflate = false; + let mut zstd = false; + + for part in env.split(',') { + match part.trim().to_lowercase().as_str() { + "gzip" => gzip = true, + "brotli" | "br" => brotli = true, + "deflate" => deflate = true, + "zstd" => zstd = true, + other => tracing::warn!( + "Unknown compression algorithm in COMPRESSION_ALGORITHMS: '{}'", + other + ), + } + } + + if !gzip && !brotli && !deflate && !zstd { + return None; + } + + let mut layer = CompressionLayer::new(); + layer = layer.gzip(gzip); + layer = layer.br(brotli); + layer = layer.deflate(deflate); + layer = layer.zstd(zstd); + Some(layer) +} + /// 程序入口 fn main() { // server feature:启动服务端 @@ -54,7 +96,6 @@ fn main() { dioxus::server::serve(|| async move { use dioxus::server::{axum, DioxusRouterExt, ServeConfig}; use std::time::Duration; - use tower_http::compression::CompressionLayer; use tower_http::timeout::TimeoutLayer; use axum::http::StatusCode; @@ -101,13 +142,16 @@ fn main() { let dioxus_app = axum::Router::new().serve_dioxus_application(config, router::AppRouter); - // 合并 Dioxus + 压缩/30s 超时中间件 - let app_routes = dioxus_app - .layer(CompressionLayer::new()) - .layer(TimeoutLayer::with_status_code( - StatusCode::REQUEST_TIMEOUT, - Duration::from_secs(30), - )); + // 合并 Dioxus + 可选压缩/30s 超时中间件 + let app_routes = if let Some(layer) = compression_layer_from_env() { + dioxus_app.layer(layer) + } else { + dioxus_app + } + .layer(TimeoutLayer::with_status_code( + StatusCode::REQUEST_TIMEOUT, + Duration::from_secs(30), + )); // 静态资源路由:图片文件服务。 // 注意:axum 0.8 没有 ConnectInfoLayer,且 dioxus::server::serve 不会把 @@ -124,7 +168,7 @@ fn main() { axum::routing::get(|| async { StatusCode::NOT_FOUND }), ); - // 合并:upload 路由保持自己独立的 300s 超时;app routes 加压缩/30s;static routes 无任何中间件 + // 合并:upload 路由保持自己独立的 300s 超时;app routes 加可选压缩/30s;static routes 无任何中间件 let router = upload_route.merge(app_routes).merge(static_routes); Ok(router)