salvo-middleware
Implement middleware for authentication, logging, CORS, and request processing. Use for cross-cutting concerns and request/response modification.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Implement middleware for authentication, logging, CORS, and request processing. Use for cross-cutting concerns and request/response modification.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
Guide for using RBatis v4 Rust ORM framework. Use when implementing database CRUD operations, writing dynamic SQL with py_sql or html_sql macros, configuring database connections, managing transactions, implementing interceptors, syncing table structures, or integrating RBatis into Genies microservices. Also use when the user asks about RBatis usage patterns, query building, or database operations in Rust.
Genies 前后端接口规范。Use when designing API contracts, defining field naming conventions, date/time formats, response models, pagination, error handling, or ID strategies between Genies backend and frontend (Web/Android/OHOS).
Guide for using flyway-rs database migration framework with RBatis. Use when implementing database schema migrations, managing SQL changelog files, configuring migration runners, handling multi-database migrations, or integrating database versioning into Genies microservices.
Guide for developing Rust microservices using Genies framework following Java DDD layering principles. Use when creating new microservices, designing aggregate roots, implementing domain events, organizing service layers, setting up Flyway migrations, or structuring a DDD-based Genies project.
Genies framework unified skill hub. Use when you need to find the right skill for any Genies framework task, including authentication, authorization, caching, configuration, database, DDD microservices, Dapr messaging, macros, K8s deployment, testing, API conventions, gateway proxy, or Salvo web framework features. Also use when the user asks about Genies framework capabilities, asks which skill to use, or wants a quick overview of available Genies skills.
Guide for using the Genies Rust microservice framework with DDD and Dapr. Use when developing with Genies, creating aggregates, domain events, Dapr subscriptions, Casbin field-level permissions, configuration management, or when the user asks about Genies framework usage patterns.
| name | salvo-middleware |
| description | Implement middleware for authentication, logging, CORS, and request processing. Use for cross-cutting concerns and request/response modification. |
| version | 0.89.3 |
| tags | ["core","middleware","hoop","flow-ctrl"] |
This skill helps implement middleware in Salvo applications. In Salvo, middleware is just a handler with flow control - the same concept applies to both.
Middleware uses FlowCtrl to control execution flow:
use 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));
}
Use hoop() to attach middleware:
let router = Router::new()
.hoop(logger)
.hoop(auth_check)
.get(handler);
Middleware applies to all child routes:
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 check
let 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);
Store data in middleware for use in handlers:
#[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);
}
Stop execution and return response immediately:
#[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;
}
FlowCtrl provides methods to control middleware chain execution:
call_next(): Call the next middleware or handlerskip_rest(): Skip remaining middleware and handlersis_ceased(): Check if execution has been stoppedSalvo provides many built-in middleware:
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 |
|---|---|---|
Logger | logging | Request/response logging |
Compression | compression | Response compression (gzip, brotli) |
Cors | cors | Cross-Origin Resource Sharing |
Timeout | timeout | Request timeout handling |
CsrfHandler | csrf | CSRF protection |
RateLimiter | rate-limiter | Rate limiting |
ConcurrencyLimiter | concurrency-limiter | Concurrent request limiting |
SizeLimiter | size-limiter | Request body size limiting |
Middleware executes in an onion-like pattern:
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() to continue executionctrl.skip_rest() to stop earlyDepot