Loading...
Loading...
Implement middleware for authentication, logging, CORS, and request processing. Use for cross-cutting concerns and request/response modification.
npx skill4agent add salvo-rs/salvo-skills salvo-middlewareFlowCtrluse salvo::prelude::*;
#[handler]
async fn logger(req: &mut Request, depot: &mut Depot, res: &mut Response, ctrl: &mut FlowCtrl) {
println!("Request: {} {}", req.method(), req.uri().path());
// Continue to next handler
ctrl.call_next(req, depot, res).await;
println!("Response status: {}", res.status_code().unwrap_or(StatusCode::OK));
}hoop()let router = Router::new()
.hoop(logger)
.hoop(auth_check)
.get(handler);let router = Router::new()
.push(
Router::with_path("api")
.hoop(auth_check) // Only applies to /api routes
.get(protected_handler)
)
.get(public_handler); // No auth checklet router = Router::new()
.hoop(global_middleware) // Applies to all routes
.push(Router::with_path("/api").get(api_handler))
.push(Router::with_path("/admin").get(admin_handler));let router = Router::new()
.push(
Router::with_path("/api")
.hoop(api_middleware) // Only applies to /api
.get(api_handler)
)
.push(Router::with_path("/admin").get(admin_handler));let router = Router::new()
.hoop(logger) // Global logging
.push(
Router::with_path("/api")
.hoop(auth_middleware) // API authentication
.hoop(rate_limiter) // API rate limiting
.get(api_handler)
)
.push(
Router::with_path("/public")
.get(public_handler) // No auth required
);#[handler]
async fn auth_check(req: &mut Request, depot: &mut Depot, res: &mut Response, ctrl: &mut FlowCtrl) {
let token = req.header::<String>("Authorization");
match token {
Some(token) if validate_token(&token) => {
depot.insert("user_id", extract_user_id(&token));
ctrl.call_next(req, depot, res).await;
}
_ => {
res.status_code(StatusCode::UNAUTHORIZED);
res.render("Unauthorized");
ctrl.skip_rest();
}
}
}#[handler]
async fn request_logger(req: &mut Request, depot: &mut Depot, res: &mut Response, ctrl: &mut FlowCtrl) {
let start = std::time::Instant::now();
let method = req.method().clone();
let path = req.uri().path().to_string();
ctrl.call_next(req, depot, res).await;
let duration = start.elapsed();
let status = res.status_code().unwrap_or(StatusCode::OK);
println!("{} {} - {} ({:?})", method, path, status, duration);
}#[handler]
async fn add_custom_header(req: &mut Request, depot: &mut Depot, res: &mut Response, ctrl: &mut FlowCtrl) {
res.headers_mut().insert("X-Custom-Header", "Salvo".parse().unwrap());
ctrl.call_next(req, depot, res).await;
}use salvo::cors::Cors;
use salvo::http::Method;
let cors = Cors::new()
.allow_origin("https://example.com")
.allow_methods(vec![Method::GET, Method::POST, Method::PUT, Method::DELETE])
.allow_headers(vec!["Content-Type", "Authorization"])
.into_handler();
let router = Router::new().hoop(cors);use salvo::rate_limiter::{RateLimiter, FixedGuard, RemoteIpIssuer, BasicQuota, MokaStore};
use std::time::Duration;
let limiter = RateLimiter::new(
FixedGuard::new(),
MokaStore::new(),
RemoteIpIssuer,
BasicQuota::per_second(10),
);
let router = Router::new().hoop(limiter);#[handler]
async fn auth_middleware(req: &mut Request, depot: &mut Depot, res: &mut Response, ctrl: &mut FlowCtrl) {
let user = authenticate(req).await;
depot.insert("user", user);
ctrl.call_next(req, depot, res).await;
}
#[handler]
async fn protected_handler(depot: &mut Depot) -> String {
let user = depot.get::<User>("user").unwrap();
format!("Hello, {}", user.name)
}// Store different types
depot.insert("string_value", "hello");
depot.insert("int_value", 42);
depot.insert("bool_value", true);
// Safely retrieve values (type must match)
if let Some(str_val) = depot.get::<&str>("string_value") {
println!("String value: {}", str_val);
}
if let Some(int_val) = depot.get::<i32>("int_value") {
println!("Int value: {}", int_val);
}#[handler]
async fn validate_input(req: &mut Request, depot: &mut Depot, res: &mut Response, ctrl: &mut FlowCtrl) {
if !is_valid_request(req) {
res.status_code(StatusCode::BAD_REQUEST);
res.render("Invalid request");
ctrl.skip_rest(); // Stop processing
return;
}
ctrl.call_next(req, depot, res).await;
}FlowCtrlcall_next()skip_rest()is_ceased()use salvo::compression::Compression;
use salvo::cors::Cors;
use salvo::logging::Logger;
use salvo::timeout::Timeout;
use std::time::Duration;
let router = Router::new()
.hoop(Logger::new())
.hoop(Compression::new())
.hoop(Cors::permissive())
.hoop(Timeout::new(Duration::from_secs(30)));| Middleware | Feature | Description |
|---|---|---|
| | Request/response logging |
| | Response compression (gzip, brotli) |
| | Cross-Origin Resource Sharing |
| | Request timeout handling |
| | CSRF protection |
| | Rate limiting |
| | Concurrent request limiting |
| | Request body size limiting |
Router::new()
.hoop(middleware_a) // Runs first (outer layer)
.hoop(middleware_b) // Runs second
.hoop(middleware_c) // Runs third (inner layer)
.get(handler); // Core handler
// Execution order:
// middleware_a (before) -> middleware_b (before) -> middleware_c (before)
// -> handler
// -> middleware_c (after) -> middleware_b (after) -> middleware_a (after)ctrl.call_next()ctrl.skip_rest()Depot