Compress HTTP responses using gzip, brotli, zstd, or deflate. Use for reducing bandwidth and improving load times.
Install
npx skillscat add salvo-rs/salvo-skills/salvo-compression Install via the SkillsCat registry.
SKILL.md
Salvo Response Compression
This skill helps configure response compression in Salvo applications.
HTTP Compression Basics
HTTP compression reduces response size by compressing content before sending. The process:
- Client sends
Accept-Encoding: gzip, deflate, brheader - Server compresses response and sets
Content-Encoding: gzipheader - Client automatically decompresses the response
Setup
[dependencies]
salvo = { version = "0.89.0", features = ["compression"] }Basic Usage
use salvo::prelude::*;
use salvo::compression::Compression;
#[handler]
async fn large_response() -> String {
"This response will be compressed if the client supports it. ".repeat(100)
}
#[tokio::main]
async fn main() {
let router = Router::new()
.hoop(Compression::new()) // Enable compression
.get(large_response);
let acceptor = TcpListener::new("0.0.0.0:8080").bind().await;
Server::new(acceptor).serve(router).await;
}Supported Algorithms
Salvo supports four compression algorithms:
| Algorithm | Feature | Description |
|---|---|---|
| Gzip | Default | Most widely supported, good balance |
| Brotli (br) | Default | Best compression ratio, higher CPU |
| Zstd | Default | Fast with good compression |
| Deflate | Default | Legacy, rarely used alone |
Configuring Specific Algorithms
use salvo::compression::{Compression, CompressionLevel};
// Only gzip
let gzip_only = Compression::new()
.enable_gzip(CompressionLevel::Default);
// Only brotli
let brotli_only = Compression::new()
.enable_brotli(CompressionLevel::Best);
// Multiple algorithms
let multi = Compression::new()
.enable_gzip(CompressionLevel::Default)
.enable_brotli(CompressionLevel::Default)
.enable_zstd(CompressionLevel::Default);Compression Levels
use salvo::compression::CompressionLevel;
// Available levels
CompressionLevel::Fastest // Fastest speed, lower compression
CompressionLevel::Default // Balanced speed and compression
CompressionLevel::Best // Best compression, slower
CompressionLevel::Precise(6) // Exact level (algorithm-specific)Level Selection Guide
| Use Case | Recommended Level |
|---|---|
| Dynamic API responses | Fastest |
| Static assets | Best |
| General purpose | Default |
Minimum Response Size
Small responses may become larger after compression. Set a minimum threshold:
let compression = Compression::new()
.min_length(1024); // Only compress responses > 1KBContent Type Filtering
Only compress text-based content (default behavior):
let compression = Compression::new()
.content_types(vec![
"text/html",
"text/css",
"text/javascript",
"application/json",
"application/xml",
"image/svg+xml",
]);Algorithm Priority
When client supports multiple algorithms, set server preference:
let compression = Compression::new()
.force_priority(true); // Use server's priority order
// Default priority: Brotli > Zstd > Gzip > DeflateDifferent Routes, Different Compression
use salvo::compression::{Compression, CompressionLevel};
use salvo::prelude::*;
#[tokio::main]
async fn main() {
// High compression for static assets
let static_compression = Compression::new()
.enable_brotli(CompressionLevel::Best)
.enable_gzip(CompressionLevel::Best);
// Fast compression for API
let api_compression = Compression::new()
.enable_gzip(CompressionLevel::Fastest)
.min_length(256);
let router = Router::new()
.push(
Router::with_path("static")
.hoop(static_compression)
.get(StaticDir::new("./public"))
)
.push(
Router::with_path("api")
.hoop(api_compression)
.get(api_handler)
);
let acceptor = TcpListener::new("0.0.0.0:8080").bind().await;
Server::new(acceptor).serve(router).await;
}Pre-compressed Static Files
For best performance, pre-compress static files at build time:
# Pre-compress with gzip
gzip -k -9 ./public/bundle.js
# Pre-compress with brotli
brotli -k ./public/bundle.jsThen serve with static file handler that detects pre-compressed files.
Complete Example
use salvo::compression::{Compression, CompressionLevel};
use salvo::prelude::*;
use serde::Serialize;
#[derive(Serialize)]
struct LargeResponse {
items: Vec<String>,
}
#[handler]
async fn large_json() -> Json<LargeResponse> {
Json(LargeResponse {
items: (0..1000).map(|i| format!("Item {}", i)).collect(),
})
}
#[handler]
async fn html_page() -> Text<&'static str> {
Text::Html(r#"
<!DOCTYPE html>
<html>
<head><title>Compressed Page</title></head>
<body>
<h1>This page is compressed!</h1>
<p>The server compresses this HTML before sending it.</p>
</body>
</html>
"#)
}
#[tokio::main]
async fn main() {
let compression = Compression::new()
.enable_gzip(CompressionLevel::Default)
.enable_brotli(CompressionLevel::Default)
.min_length(512)
.content_types(vec![
"text/html",
"text/css",
"application/json",
"application/javascript",
]);
let router = Router::new()
.hoop(compression)
.push(Router::with_path("api/data").get(large_json))
.push(Router::with_path("page").get(html_page));
let acceptor = TcpListener::new("0.0.0.0:8080").bind().await;
Server::new(acceptor).serve(router).await;
}Testing Compression
# Request with gzip support
curl -H "Accept-Encoding: gzip" -v http://localhost:8080/api/data
# Request with brotli support
curl -H "Accept-Encoding: br" -v http://localhost:8080/api/data
# Check response headers for Content-EncodingBest Practices
- Use compression for text content: HTML, CSS, JS, JSON, XML
- Skip already compressed content: JPEG, PNG, MP4, ZIP
- Set minimum size threshold: Avoid compressing tiny responses
- Choose level based on content type: Static = Best, Dynamic = Fastest
- Pre-compress static assets: Build-time compression for best performance
- Monitor CPU usage: High compression levels increase CPU load
- Test with real clients: Verify compression works end-to-end
- Consider CDN compression: CDNs often handle compression for you