Skip to content

Commit d539875

Browse files
committed
路由参数匹配异常修复
添加路由参数匹配示例
1 parent ca4d5bb commit d539875

File tree

6 files changed

+91
-22
lines changed

6 files changed

+91
-22
lines changed

examples/path_params/Cargo.toml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
[package]
2+
name = "path_params"
3+
version = "0.1.0"
4+
edition = "2021"
5+
6+
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
7+
8+
[dependencies]
9+
silent = { version = "0.1.0", path = "../../silent" }

examples/path_params/src/main.rs

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
use silent::prelude::*;
2+
3+
fn main() {
4+
logger::fmt().with_max_level(Level::INFO).init();
5+
// 定义路由
6+
let route = Route::new("path_params")
7+
.append(Route::new("<key:str>/str").get(hello_world))
8+
.append(Route::new("<key:int>/int").get(hello_world))
9+
.append(Route::new("<key:uuid>/uuid").get(hello_world))
10+
.append(Route::new("<key:path>/path").get(hello_world))
11+
.append(Route::new("<key:full_path>/full_path").get(hello_world))
12+
.append(Route::new("<key:*>/*").get(hello_world))
13+
.append(Route::new("<key:**>/**").get(hello_world))
14+
.append(Route::new("<key>").get(hello_world))
15+
.append(Route::new("<key:other>/other").get(hello_world));
16+
println!("{:?}", route);
17+
Server::new().bind_route(route).run();
18+
}
19+
20+
// 定义处理方法
21+
async fn hello_world(req: Request) -> Result<String, SilentError> {
22+
let path_params = req.get_path_params("key").unwrap();
23+
match path_params {
24+
PathParam::String(str) => Ok(format!("str {}", str)),
25+
PathParam::Int(int) => Ok(format!("int {}", int)),
26+
PathParam::UUid(uuid) => Ok(format!("uuid {}", uuid)),
27+
PathParam::Path(path) => Ok(format!("path {}", path)),
28+
}
29+
}

silent/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ pub(crate) use handler::{Handler, HandlerWrapper};
1515
pub use hyper::Method;
1616

1717
pub mod prelude {
18-
pub use crate::core::{request::Request, response::Response};
18+
pub use crate::core::{path_param::PathParam, request::Request, response::Response};
1919
pub use crate::error::SilentError;
2020
pub use crate::log::{logger, Level};
2121
pub use crate::route::handler_append::HandlerAppend;

silent/src/route/handler_append.rs

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,18 @@ where
6161
}
6262

6363
fn get_handler_mut(&mut self) -> &mut HashMap<Method, Arc<dyn Handler>> {
64-
&mut self.handler
64+
if self.path == self.create_path {
65+
&mut self.handler
66+
} else {
67+
let mut iter = self.create_path.splitn(2, '/');
68+
let _local_url = iter.next().unwrap_or("");
69+
let last_url = iter.next().unwrap_or("");
70+
let route = self
71+
.children
72+
.iter_mut()
73+
.find(|c| c.create_path == last_url)
74+
.unwrap();
75+
<Route as HandlerAppend<F, T, Fut>>::get_handler_mut(route)
76+
}
6577
}
6678
}

silent/src/route/handler_match.rs

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,6 @@ impl<'a> From<&'a str> for SpecialPath {
5454
impl Match for Route {
5555
fn handler_match(&self, req: &mut Request, path: &str) -> RouteMatched {
5656
let (local_url, last_url) = Self::path_split(path);
57-
5857
if !self.special_match {
5958
if self.path == local_url {
6059
self.last_matched(req, last_url)
@@ -63,10 +62,13 @@ impl Match for Route {
6362
}
6463
} else {
6564
match self.get_path().into() {
66-
SpecialPath::String(key) => {
67-
req.set_path_params(key, local_url.to_string().into());
68-
self.last_matched(req, last_url)
69-
}
65+
SpecialPath::String(key) => match self.last_matched(req, last_url) {
66+
RouteMatched::Matched(route) => {
67+
req.set_path_params(key, local_url.to_string().into());
68+
RouteMatched::Matched(route)
69+
}
70+
RouteMatched::Unmatched => RouteMatched::Unmatched,
71+
},
7072
SpecialPath::Int(key) => match local_url.parse::<i32>() {
7173
Ok(value) => {
7274
req.set_path_params(key, value.into());
@@ -89,7 +91,10 @@ impl Match for Route {
8991
req.set_path_params(key, PathParam::Path(path.to_string()));
9092
match self.last_matched(req, last_url) {
9193
RouteMatched::Matched(route) => RouteMatched::Matched(route),
92-
RouteMatched::Unmatched => RouteMatched::Matched(self.clone()),
94+
RouteMatched::Unmatched => match self.handler.is_empty() {
95+
true => RouteMatched::Unmatched,
96+
false => RouteMatched::Matched(self.clone()),
97+
},
9398
}
9499
}
95100
}
@@ -103,7 +108,7 @@ impl RouteMatch for Route {
103108
}
104109

105110
fn last_matched(&self, req: &mut Request, last_url: &str) -> RouteMatched {
106-
if last_url.is_empty() {
111+
if last_url.is_empty() && !self.handler.is_empty() {
107112
return RouteMatched::Matched(self.clone());
108113
} else {
109114
for route in &self.children {

silent/src/route/mod.rs

Lines changed: 27 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use crate::route::handler_match::{Match, RouteMatched};
55
use crate::Method;
66
use hyper::StatusCode;
77
use std::collections::HashMap;
8-
use std::fmt::Display;
8+
use std::fmt;
99
use std::sync::Arc;
1010

1111
pub(crate) mod handler_append;
@@ -18,18 +18,31 @@ pub struct Route {
1818
pub children: Vec<Route>,
1919
pub middlewares: Vec<Arc<dyn Handler>>,
2020
special_match: bool,
21+
create_path: String,
2122
}
2223

23-
impl Display for Route {
24-
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
25-
let mut path = self.path.clone();
26-
if path.is_empty() {
27-
path = "/".to_string();
24+
impl fmt::Debug for Route {
25+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
26+
fn get_route_str(pre_fix: String, route: &Route) -> String {
27+
let space_pre_fix = format!(" {}", pre_fix);
28+
let mut route_strs: Vec<String> = route
29+
.children
30+
.iter()
31+
.filter(|r| !r.handler.is_empty() || !r.children.is_empty())
32+
.map(|r| get_route_str(space_pre_fix.clone(), r))
33+
.collect();
34+
if !route.handler.is_empty() || !route.children.is_empty() {
35+
let methods: Vec<String> = route.handler.keys().map(|m| m.to_string()).collect();
36+
let methods_str = if methods.is_empty() {
37+
"".to_string()
38+
} else {
39+
format!("({})", methods.join(","))
40+
};
41+
route_strs.insert(0, format!("{}{}{}", pre_fix, route.path, methods_str));
42+
}
43+
route_strs.join("\n")
2844
}
29-
for route in &self.children {
30-
write!(f, "{}", route)?;
31-
}
32-
write!(f, "{}", path)
45+
write!(f, "{}", get_route_str("".to_string(), self))
3346
}
3447
}
3548

@@ -44,6 +57,7 @@ impl Route {
4457
children: Vec::new(),
4558
middlewares: Vec::new(),
4659
special_match: first_path.starts_with('<') && first_path.ends_with('>'),
60+
create_path: path.to_string(),
4761
};
4862
if last_path.is_empty() {
4963
route
@@ -62,12 +76,12 @@ pub struct Routes {
6276
pub children: Vec<Route>,
6377
}
6478

65-
impl Display for Routes {
66-
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
79+
impl fmt::Debug for Routes {
80+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
6781
let path = self
6882
.children
6983
.iter()
70-
.map(|route| route.to_string())
84+
.map(|route| format!("{:?}", route))
7185
.collect::<Vec<String>>()
7286
.join("\n");
7387
write!(f, "{}", path)

0 commit comments

Comments
 (0)