salvo-routing
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseSalvo Routing
Salvo 路由
This skill helps configure advanced routing patterns in Salvo applications.
本技能可帮助你在Salvo应用中配置高级路由模式。
Salvo Routing Innovation
Salvo 路由的创新特性
Salvo's routing system has unique features:
- Path as Filter: Path matching is essentially a filter, allowing unified combination with method and custom conditions
- Reusable Routes: Routers can be added to multiple locations for flexible composition
- Unified Middleware Model: Middleware and handlers share the same concept via method
hoop() - Flexible Nesting: Use for arbitrary depth hierarchical structures
push()
Salvo的路由系统具备独特特性:
- 路径作为过滤器:路径匹配本质上是一种过滤器,可与请求方法、自定义条件统一组合
- 可复用路由:路由器可添加到多个位置,实现灵活组合
- 统一中间件模型:中间件与处理器通过方法共享同一概念
hoop() - 灵活嵌套:使用方法构建任意深度的层级结构
push()
Path Patterns
路径模式
Static Paths
静态路径
rust
Router::with_path("users").get(list_users)rust
Router::with_path("users").get(list_users)Path Parameters
路径参数
Salvo uses syntax for path parameters (since version 0.76). Earlier versions used syntax, which is now deprecated.
{id}<id>rust
// Basic parameter
Router::with_path("users/{id}").get(show_user)
// Typed parameter (num, i32, i64, etc.)
Router::with_path("users/{id:num}").get(show_user)
// Regex pattern
Router::with_path(r"users/{id|\d+}").get(show_user)
// Wildcard (captures rest of path)
Router::with_path("files/{**path}").get(serve_file)Salvo(从0.76版本开始)使用语法定义路径参数。早期版本使用的语法现已废弃。
{id}<id>rust
// 基础参数
Router::with_path("users/{id}").get(show_user)
// 类型化参数(num, i32, i64等)
Router::with_path("users/{id:num}").get(show_user)
// 正则表达式模式
Router::with_path(r"users/{id|\d+}").get(show_user)
// 通配符(捕获剩余路径)
Router::with_path("files/{**path}").get(serve_file)Accessing Parameters
获取参数
rust
#[handler]
async fn show_user(req: &mut Request) -> String {
let id = req.param::<i64>("id").unwrap();
format!("User ID: {}", id)
}rust
#[handler]
async fn show_user(req: &mut Request) -> String {
let id = req.param::<i64>("id").unwrap();
format!("User ID: {}", id)
}Wildcard Types
通配符类型
Salvo supports multiple wildcard patterns (using syntax since version 0.76; earlier versions used syntax):
{}<>-
: Matches any single path segment
{*}rustRouter::new().path("{*}").get(catch_all) -
: Matches all remaining path segments (including slashes)
{**}rustRouter::new().path("static/{**path}").get(serve_static) // Matches: static/css/style.css, static/js/main.js, etc. -
Named wildcards: Can retrieve matched content in handlerrust
Router::new().path("files/{*rest}").get(handler) // In handler: req.param::<String>("rest")
Salvo支持多种通配符模式(从0.76版本开始使用语法;早期版本使用语法):
{}<>-
:匹配任意单个路径段
{*}rustRouter::new().path("{*}").get(catch_all) -
:匹配所有剩余路径段(包括斜杠)
{**}rustRouter::new().path("static/{**path}").get(serve_static) // 匹配:static/css/style.css, static/js/main.js等 -
命名通配符:可在处理器中获取匹配内容rust
Router::new().path("files/{*rest}").get(handler) // 在处理器中:req.param::<String>("rest")
Nested Routers
嵌套路由器
Tree Structure
树形结构
rust
let router = Router::new()
.push(
Router::with_path("api/v1")
.push(
Router::with_path("users")
.get(list_users)
.post(create_user)
.push(
Router::with_path("{id}")
.get(show_user)
.patch(update_user)
.delete(delete_user)
)
)
.push(
Router::with_path("posts")
.get(list_posts)
.post(create_post)
)
);rust
let router = Router::new()
.push(
Router::with_path("api/v1")
.push(
Router::with_path("users")
.get(list_users)
.post(create_user)
.push(
Router::with_path("{id}")
.get(show_user)
.patch(update_user)
.delete(delete_user)
)
)
.push(
Router::with_path("posts")
.get(list_posts)
.post(create_post)
)
);Route Composition
路由组合
rust
fn user_routes() -> Router {
Router::with_path("users")
.get(list_users)
.post(create_user)
.push(
Router::with_path("{id}")
.get(get_user)
.patch(update_user)
.delete(delete_user)
)
}
fn post_routes() -> Router {
Router::with_path("posts")
.get(list_posts)
.post(create_post)
}
let api_v1 = Router::with_path("v1")
.push(user_routes())
.push(post_routes());
let api_v2 = Router::with_path("v2")
.push(user_routes())
.push(post_routes());
let router = Router::new()
.push(Router::with_path("api/v1/users").get(list_users).post(create_user))
.push(Router::with_path("api/v1/users/{id}").get(show_user).patch(update_user).delete(delete_user));rust
fn user_routes() -> Router {
Router::with_path("users")
.get(list_users)
.post(create_user)
.push(
Router::with_path("{id}")
.get(get_user)
.patch(update_user)
.delete(delete_user)
)
}
fn post_routes() -> Router {
Router::with_path("posts")
.get(list_posts)
.post(create_post)
}
let api_v1 = Router::with_path("v1")
.push(user_routes())
.push(post_routes());
let api_v2 = Router::with_path("v2")
.push(user_routes())
.push(post_routes());
let router = Router::new()
.push(Router::with_path("api/v1/users").get(list_users).post(create_user))
.push(Router::with_path("api/v1/users/{id}").get(show_user).patch(update_user).delete(delete_user));HTTP Methods
HTTP 请求方法
rust
Router::new()
.get(handler) // GET
.post(handler) // POST
.put(handler) // PUT
.patch(handler) // PATCH
.delete(handler) // DELETE
.head(handler) // HEAD
.options(handler); // OPTIONSrust
Router::new()
.get(handler) // GET
.post(handler) // POST
.put(handler) // PUT
.patch(handler) // PATCH
.delete(handler) // DELETE
.head(handler) // HEAD
.options(handler); // OPTIONSPath Matching Behavior
路径匹配机制
When a request arrives, routing works as follows:
- Filter Matching: First attempts to match route filters (path, method, etc.)
- Match Failed: If no filter matches, that route's middleware and handler are skipped
- Match Success: If matched, executes middleware and handler in order
rust
use salvo::routing::filters;
// Path filter
Router::with_filter(filters::path("users"))
// Method filter
Router::with_filter(filters::get())
// Combined filters
Router::with_filter(filters::path("users").and(filters::get()))当请求到达时,路由匹配流程如下:
- 过滤器匹配:首先尝试匹配路由过滤器(路径、请求方法等)
- 匹配失败:若没有过滤器匹配,则跳过该路由的中间件与处理器
- 匹配成功:若匹配成功,则按顺序执行中间件与处理器
rust
use salvo::routing::filters;
// 路径过滤器
Router::with_filter(filters::path("users"))
// 请求方法过滤器
Router::with_filter(filters::get())
// 组合过滤器
Router::with_filter(filters::path("users").and(filters::get()))Middleware with Routes
路由与中间件结合
Use to add middleware to routes:
hoop()rust
let router = Router::new()
.hoop(logging) // Applies to all routes
.path("api")
.push(
Router::new()
.hoop(auth_check) // Only applies to routes under this
.path("users")
.get(list_users)
.post(create_user)
);使用方法为路由添加中间件:
hoop()rust
let router = Router::new()
.hoop(logging) // 应用于所有路由
.path("api")
.push(
Router::new()
.hoop(auth_check) // 仅应用于该路由下的所有子路由
.path("users")
.get(list_users)
.post(create_user)
);HTTP Redirects
HTTP 重定向
rust
use salvo::prelude::*;
use salvo::writing::Redirect;
// Permanent redirect (301)
#[handler]
async fn permanent_redirect(res: &mut Response) {
res.render(Redirect::permanent("/new-location"));
}
// Temporary redirect (302)
#[handler]
async fn temporary_redirect(res: &mut Response) {
res.render(Redirect::found("/temporary-location"));
}
// See Other (303)
#[handler]
async fn see_other(res: &mut Response) {
res.render(Redirect::see_other("/another-page"));
}rust
use salvo::prelude::*;
use salvo::writing::Redirect;
// 永久重定向(301)
#[handler]
async fn permanent_redirect(res: &mut Response) {
res.render(Redirect::permanent("/new-location"));
}
// 临时重定向(302)
#[handler]
async fn temporary_redirect(res: &mut Response) {
res.render(Redirect::found("/temporary-location"));
}
// 查看其他地址(303)
#[handler]
async fn see_other(res: &mut Response) {
res.render(Redirect::see_other("/another-page"));
}Custom Route Filters
自定义路由过滤器
Create custom filters for complex matching logic:
rust
use salvo::prelude::*;
use salvo::routing::filter::Filter;
use uuid::Uuid;
pub struct GuidFilter;
impl Filter for GuidFilter {
fn filter(&self, req: &mut Request, _state: &mut PathState) -> bool {
if let Some(param) = req.param::<String>("id") {
Uuid::parse_str(¶m).is_ok()
} else {
false
}
}
}
#[handler]
async fn get_user_by_guid(req: &mut Request) -> String {
let id = req.param::<Uuid>("id").unwrap();
format!("User GUID: {}", id)
}
let router = Router::new()
.path("users/{id}")
.filter(GuidFilter)
.get(get_user_by_guid);创建自定义过滤器以实现复杂匹配逻辑:
rust
use salvo::prelude::*;
use salvo::routing::filter::Filter;
use uuid::Uuid;
pub struct GuidFilter;
impl Filter for GuidFilter {
fn filter(&self, req: &mut Request, _state: &mut PathState) -> bool {
if let Some(param) = req.param::<String>("id") {
Uuid::parse_str(¶m).is_ok()
} else {
false
}
}
}
#[handler]
async fn get_user_by_guid(req: &mut Request) -> String {
let id = req.param::<Uuid>("id").unwrap();
format!("User GUID: {}", id)
}
let router = Router::new()
.path("users/{id}")
.filter(GuidFilter)
.get(get_user_by_guid);Best Practices
最佳实践
- Use tree structure for complex APIs
- Use route composition functions for reusability
- Use regex constraints for path parameters when needed ()
{id:/\d+/} - Group related routes under common paths
- Use descriptive parameter names
- Apply middleware at the appropriate route level
- Prefer syntax for consistency
{id}
- 为复杂API使用树形结构
- 使用路由组合函数提升复用性
- 必要时为路径参数添加正则约束()
{id:/\d+/} - 将相关路由分组到共同路径下
- 使用描述性的参数名称
- 在合适的路由层级应用中间件
- 优先使用语法以保持一致性
{id}