salvo-proxy
Implement reverse proxy to forward requests to backend services. Use for load balancing, API gateways, and microservices routing.
Codex または Claude でインストール この Prompt をコピーして Codex、Claude、または他のアシスタントに貼り付けると、Skill ページを確認してインストールできます。
メニュー
Implement reverse proxy to forward requests to backend services. Use for load balancing, API gateways, and microservices routing.
Codex または Claude でインストール この Prompt をコピーして Codex、Claude、または他のアシスタントに貼り付けると、Skill ページを確認してインストールできます。
SOC 職業分類に基づく
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-proxy |
| description | Implement reverse proxy to forward requests to backend services. Use for load balancing, API gateways, and microservices routing. |
| version | 0.89.3 |
| tags | ["advanced","proxy","reverse-proxy","gateway"] |
This skill helps implement reverse proxy functionality in Salvo applications.
A reverse proxy accepts client requests and forwards them to backend servers. Benefits:
[dependencies]
salvo = { version = "0.89.3", features = ["proxy"] }
use salvo::prelude::*;
use salvo::proxy::{Proxy, HyperClient};
#[tokio::main]
async fn main() {
// Proxy all requests to backend
let proxy = Proxy::new(
vec!["http://localhost:3000"],
HyperClient::default(),
);
let router = Router::new()
.push(Router::with_path("{**rest}").goal(proxy));
let acceptor = TcpListener::new("0.0.0.0:8080").bind().await;
Server::new(acceptor).serve(router).await;
}
use salvo::prelude::*;
use salvo::proxy::{Proxy, ReqwestClient};
let proxy = Proxy::new(
vec!["http://localhost:3000"],
ReqwestClient::default(),
);
Distribute requests across multiple backends:
use salvo::prelude::*;
use salvo::proxy::{Proxy, HyperClient};
let proxy = Proxy::new(
vec![
"http://backend1:3000",
"http://backend2:3000",
"http://backend3:3000",
],
HyperClient::default(),
);
let router = Router::new()
.push(Router::with_path("{**rest}").goal(proxy));
Route different paths to different backends:
use salvo::prelude::*;
use salvo::proxy::{Proxy, HyperClient};
#[tokio::main]
async fn main() {
// API requests to API server
let api_proxy = Proxy::new(
vec!["http://api-server:3000"],
HyperClient::default(),
);
// Static files to static server
let static_proxy = Proxy::new(
vec!["http://static-server:8080"],
HyperClient::default(),
);
// WebSocket to WS server
let ws_proxy = Proxy::new(
vec!["http://ws-server:9000"],
HyperClient::default(),
);
let router = Router::new()
.push(Router::with_path("api/{**rest}").goal(api_proxy))
.push(Router::with_path("static/{**rest}").goal(static_proxy))
.push(Router::with_path("ws/{**rest}").goal(ws_proxy));
let acceptor = TcpListener::new("0.0.0.0:8080").bind().await;
Server::new(acceptor).serve(router).await;
}
use salvo::prelude::*;
use salvo::proxy::{Proxy, HyperClient};
#[tokio::main]
async fn main() {
// User service
let user_proxy = Proxy::new(
vec!["http://user-service:3001"],
HyperClient::default(),
);
// Order service
let order_proxy = Proxy::new(
vec!["http://order-service:3002"],
HyperClient::default(),
);
// Product service
let product_proxy = Proxy::new(
vec!["http://product-service:3003"],
HyperClient::default(),
);
let router = Router::new()
.push(
Router::with_path("api/v1")
.hoop(auth_middleware) // Apply auth to all routes
.push(Router::with_path("users/{**rest}").goal(user_proxy))
.push(Router::with_path("orders/{**rest}").goal(order_proxy))
.push(Router::with_path("products/{**rest}").goal(product_proxy))
);
let acceptor = TcpListener::new("0.0.0.0:8080").bind().await;
Server::new(acceptor).serve(router).await;
}
Add authentication before proxying:
use salvo::prelude::*;
use salvo::proxy::{Proxy, HyperClient};
#[handler]
async fn auth_middleware(req: &mut Request, depot: &mut Depot, res: &mut Response, ctrl: &mut FlowCtrl) {
let token = req.header::<String>("Authorization");
match token {
Some(t) if validate_token(&t) => {
ctrl.call_next(req, depot, res).await;
}
_ => {
res.status_code(StatusCode::UNAUTHORIZED);
res.render("Unauthorized");
ctrl.skip_rest();
}
}
}
#[tokio::main]
async fn main() {
let proxy = Proxy::new(
vec!["http://backend:3000"],
HyperClient::default(),
);
let router = Router::new()
.push(
Router::with_path("api/{**rest}")
.hoop(auth_middleware)
.goal(proxy)
);
let acceptor = TcpListener::new("0.0.0.0:8080").bind().await;
Server::new(acceptor).serve(router).await;
}
Add headers before forwarding:
use salvo::prelude::*;
#[handler]
async fn add_proxy_headers(req: &mut Request, depot: &mut Depot, res: &mut Response, ctrl: &mut FlowCtrl) {
// Add forwarded headers
if let Some(addr) = req.remote_addr() {
req.headers_mut().insert("X-Forwarded-For", addr.to_string().parse().unwrap());
}
req.headers_mut().insert("X-Forwarded-Proto", "https".parse().unwrap());
ctrl.call_next(req, depot, res).await;
}
use salvo::prelude::*;
use std::sync::Arc;
use tokio::sync::RwLock;
#[derive(Clone)]
struct HealthyBackends {
backends: Arc<RwLock<Vec<String>>>,
}
impl HealthyBackends {
async fn get_backends(&self) -> Vec<String> {
self.backends.read().await.clone()
}
async fn update_health(&self, all_backends: &[&str]) {
let mut healthy = Vec::new();
for backend in all_backends {
if check_health(backend).await {
healthy.push(backend.to_string());
}
}
*self.backends.write().await = healthy;
}
}
async fn check_health(backend: &str) -> bool {
// Implement health check logic
reqwest::get(format!("{}/health", backend))
.await
.map(|r| r.status().is_success())
.unwrap_or(false)
}
Proxy WebSocket connections:
use salvo::prelude::*;
use salvo::proxy::{Proxy, HyperClient};
let ws_proxy = Proxy::new(
vec!["http://ws-backend:9000"],
HyperClient::default(),
);
let router = Router::new()
.push(Router::with_path("ws").goal(ws_proxy));
use salvo::prelude::*;
use salvo::proxy::{Proxy, HyperClient};
use salvo::rate_limiter::{BasicQuota, FixedGuard, MokaStore, RateLimiter, RemoteIpIssuer};
#[tokio::main]
async fn main() {
let limiter = RateLimiter::new(
FixedGuard::new(),
MokaStore::new(),
RemoteIpIssuer,
BasicQuota::per_second(100),
);
let proxy = Proxy::new(
vec!["http://backend:3000"],
HyperClient::default(),
);
let router = Router::new()
.push(
Router::with_path("{**rest}")
.hoop(limiter)
.goal(proxy)
);
let acceptor = TcpListener::new("0.0.0.0:8080").bind().await;
Server::new(acceptor).serve(router).await;
}
use salvo::prelude::*;
use salvo::proxy::{Proxy, HyperClient};
use salvo::cors::Cors;
use salvo::compression::Compression;
#[handler]
async fn logging(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);
}
#[tokio::main]
async fn main() {
let cors = Cors::permissive();
let compression = Compression::new();
// Backend services
let user_proxy = Proxy::new(vec!["http://users:3001"], HyperClient::default());
let order_proxy = Proxy::new(vec!["http://orders:3002"], HyperClient::default());
let router = Router::new()
.hoop(logging)
.hoop(cors)
.hoop(compression)
.push(Router::with_path("users/{**rest}").goal(user_proxy))
.push(Router::with_path("orders/{**rest}").goal(order_proxy));
let acceptor = TcpListener::new("0.0.0.0:8080").bind().await;
Server::new(acceptor).serve(router).await;
}