23 个版本
0.8.4 | 2024 年 7 月 11 日 |
---|---|
0.8.2 | 2024 年 4 月 28 日 |
0.8.0 | 2024 年 3 月 10 日 |
0.7.3 | 2023 年 9 月 22 日 |
0.2.0 | 2020 年 12 月 23 日 |
#32 in 网络编程
4,062,006 每月下载量
在 1,762 个 Crates 中使用 (51 直接使用)
65KB
1K SLoC
matchit
高性能、零拷贝 URL 路由器。
use matchit::Router;
fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut router = Router::new();
router.insert("/home", "Welcome!")?;
router.insert("/users/{id}", "A User")?;
let matched = router.at("/users/978")?;
assert_eq!(matched.params.get("id"), Some("978"));
assert_eq!(*matched.value, "A User");
Ok(())
}
参数
该路由器支持动态路由段。这些段可以是命名参数或通配符参数。
命名参数如 /{id}
匹配直到下一个 /
或路径结束的内容。请注意,命名参数必须后跟一个 /
或路由的结束。目前不支持动态后缀。
let mut m = Router::new();
m.insert("/users/{id}", true)?;
assert_eq!(m.at("/users/1")?.params.get("id"), Some("1"));
assert_eq!(m.at("/users/23")?.params.get("id"), Some("23"));
assert!(m.at("/users").is_err());
通配符参数以 *
开头,匹配直到路径结束的内容。它们必须始终位于路由的 末尾。
let mut m = Router::new();
m.insert("/{*p}", true)?;
assert_eq!(m.at("/foo.js")?.params.get("p"), Some("foo.js"));
assert_eq!(m.at("/c/bar.css")?.params.get("p"), Some("c/bar.css"));
// note that this will not match
assert!(m.at("/").is_err());
可以在静态路由中包含字符 {
和 }
,方法是使用相同的字符进行转义。例如,字符 {
使用 {{
进行转义,而字符 }
使用 }}
进行转义。
let mut m = Router::new();
m.insert("/{{hello}}", true)?;
m.insert("/{hello}", true)?;
// match the static route
assert!(m.at("/{hello}")?.value);
// match the dynamic route
assert_eq!(m.at("/hello")?.params.get("hello"), Some("hello"));
路由优先级
静态和动态路由段可以重叠。如果重叠,则静态段将具有更高的优先级
let mut m = Router::new();
m.insert("/", "Welcome!").unwrap(); // priority: 1
m.insert("/about", "About Me").unwrap(); // priority: 1
m.insert("/{*filepath}", "...").unwrap(); // priority: 2
它是如何工作的?
路由器利用了 URL 路由通常遵循层次结构的这一事实。将它们存储在基数 trie 中,该 trie 重用共同的前缀。
Priority Path Value
9 \ 1
3 ├s None
2 |├earch\ 2
1 |└upport\ 3
2 ├blog\ 4
1 | └{post} None
1 | └\ 5
2 ├about-us\ 6
1 | └team\ 7
1 └contact\ 8
这使我们能够将路由搜索减少到少数几个分支。树的同级子节点也按注册值的数量进行优先排序,增加了第一次尝试就选择正确分支的机会。
基准测试
实际上,这种方法的路由速度非常快。在一个将4条路径与130条注册路由进行匹配的基准测试中,matchit
在200纳秒内就找到了正确的路由,比大多数其他路由器快一个数量级。您可以在这里查看基准测试代码。
Compare Routers/matchit
time: [175.96 ns 176.39 ns 176.84 ns]
Compare Routers/actix
time: [26.805 us 26.811 us 26.816 us]
Compare Routers/path-tree
time: [468.95 ns 470.34 ns 471.65 ns]
Compare Routers/regex
time: [22.539 us 22.584 us 22.639 us]
Compare Routers/route-recognizer
time: [3.7552 us 3.7732 us 3.8027 us]
Compare Routers/routefinder
time: [5.7313 us 5.7405 us 5.7514 us]
致谢
这个包中的大量代码基于Julien Schmidt的httprouter
。