2个不稳定版本
0.2.2 | 2022年1月15日 |
---|---|
0.2.1 |
|
0.1.0 | 2021年12月22日 |
#9 in #http-router
每月 28 次下载
71KB
657 行代码
高性能HTTP路由器
最初作为Python的Squall API框架的路由子系统。
旨在减轻大规模路由表的开销。
风暴路由器避免大量正则表达式处理,仅在绝对必要的地方进行验证
主要概念是使用基于HashMap的数据库查找相关的处理程序。然后仅对适合的实体进行计算,而不是整个表。正则表达式匹配仅针对已定义数据验证器的字段执行。
适用于
- API网关
- API服务,其中由于参数值众多,不能使用路由缓存
- 仅确保在添加一批新端点后,路由不是性能下降的点
性能
基于matchit和actix-router代码的基准测试,因此它们也在此作为参考。
用法
use squall_router::SquallRouter;
fn main() {
let mut router = SquallRouter::new();
router.set_ignore_trailing_slashes();
router
.add_validator("int".to_string(), r"[0-9]+".to_string())
.unwrap();
router
.add_validator(
"uuid".to_string(),
r"[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}".to_string(),
)
.unwrap();
router.add_route(
"GET".to_string(),
"/route/without/dynamic/octets".to_string(),
0,
);
router.add_route(
"GET".to_string(),
"/route/aaa/{string_param}/bbb/{num_param:int}/ccc/{uuid_param:uuid}".to_string(),
1,
);
router.add_location("GET".to_string(), "/files/css".to_string(), 2);
let (handler_0, _parameters_0) = router
.resolve("GET", "/route/without/dynamic/octets")
.unwrap();
assert_eq!(handler_0, 0);
let (handler_1, parameters_1) = router
.resolve(
"GET",
"/route/aaa/aaa_value/bbb/1234/ccc/4bea5a51-1b80-4433-be06-d52726015591",
)
.unwrap();
assert_eq!(handler_1, 1);
assert_eq!(parameters_1, vec![
("string_param", "aaa_value"),
("num_param", "1234"),
("uuid_param", "4bea5a51-1b80-4433-be06-d52726015591")]
);
let (handler_2, _parameters_2) = router
.resolve("GET", "/files/css/vendor/style.css")
.unwrap();
assert_eq!(handler_2, 2);
}
HashDoS安全性说明
该组件的路由数据库基于rustc_hash::FxHashMap,这是一个非加密哈希。
在这里它适用且安全,因为数据库仅由端点注册填充,而不是在请求处理期间。
限制
目前,有两个已知的限制
具有相同长度的路由,其中包含相同位置上的混合动态
和静态
参数
/api/v1/user/{user_id}/info/full
/api/v1/user/parameter/{prm}/details
在这种情况下,请求到/api/v1/user/parameter/info/full
将找不到处理程序。这仅适用于至少包含一个动态参数并且具有相同字节数的路由。我们检查了多少API有这种行为,不到1%,可以很容易地与这个合同一致。
在下一个版本中,它将通过断言来处理,以防止不良的用户体验。
正在讨论几种方法来使这些限制不适用。
通配符路由后缀
/static/{path:.*}
- 动态路由部分取决于字节分割,因此不适用。
相反,您应该使用位置API。
依赖项
~2.2–4MB
~64K SLoC