perf(http): single smart compression layer — stop compressing media on /api
The /api router added its own predicate-less CompressionLayer (routes.rs), nested inside the global predicate-aware one in main.rs. As the inner layer it compressed responses first, so the global predicate that skips already- compressed media was bypassed for every /api response: video/audio/image/zip downloads got Brotli-compressed (CPU + first-byte latency for ~0 bytes saved) and lost their Content-Length (forced to chunked -> no client progress bar). - Remove the redundant /api CompressionLayer; /api now flows through the single global layer in main.rs. - Make that predicate smarter: compress by default so nothing shrinkable is missed, and skip ONLY already-compressed types. It no longer blanket-excludes image/*, so image/svg+xml (text, ~70% shrink) now compresses; raster formats are listed individually. Added the previously-missed already-compressed types: Office (docx/xlsx/pptx), ODF, epub, jar, apk, 7z/rar/bzip2/zstd/xz, woff/woff2 fonts, icons. Net: media downloads keep Content-Length and skip pointless compression, while text/JSON/JS/CSS/SVG/XML/ttf/otf/wasm still compress. fmt + clippy clean. https://claude.ai/code/session_01UtfkS3nZF1vrF5jNAps6wV
This commit is contained in:
@@ -9,7 +9,7 @@ use axum::{
|
||||
};
|
||||
use serde_json::json;
|
||||
use std::sync::Arc;
|
||||
use tower_http::{compression::CompressionLayer, trace::TraceLayer};
|
||||
use tower_http::trace::TraceLayer;
|
||||
use utoipa::OpenApi;
|
||||
|
||||
/// Liveness probe — returns 200 if the process is running, no DB check.
|
||||
@@ -579,10 +579,10 @@ pub fn create_api_routes(app_state: &Arc<AppState>) -> Router<Arc<AppState>> {
|
||||
.with_state(app_state.clone());
|
||||
router = router.nest("/users", users_router);
|
||||
|
||||
// Transparent compression (gzip + brotli) for all API responses.
|
||||
// tower-http negotiates via Accept-Encoding and skips already-compressed
|
||||
// content types automatically. No manual compression in handlers.
|
||||
router
|
||||
.layer(CompressionLayer::new().br(true).gzip(true))
|
||||
.layer(TraceLayer::new_for_http())
|
||||
// Compression is applied once, globally, in `main.rs` with a content-type
|
||||
// aware predicate that skips already-compressed media. Re-applying it here
|
||||
// would double-wrap `/api`: this inner layer (no predicate) would compress
|
||||
// media downloads, burning CPU for ~0 gain and stripping `Content-Length`.
|
||||
// So this router only adds tracing; compression is the global layer's job.
|
||||
router.layer(TraceLayer::new_for_http())
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user