#路由 #路由器 #HTTP路由器 #风暴

squall-router

带有路径参数提取的HTTP路由器

2个不稳定版本

0.2.2 2022年1月15日
0.2.1 2022年1月14日
0.1.0 2021年12月22日

#9 in #http-router

每月 28 次下载

MIT/Apache

71KB
657 行代码

高性能HTTP路由器

最初作为Python的Squall API框架的路由子系统。

旨在减轻大规模路由表的开销。

风暴路由器避免大量正则表达式处理,仅在绝对必要的地方进行验证

主要概念是使用基于HashMap的数据库查找相关的处理程序。然后仅对适合的实体进行计算,而不是整个表。正则表达式匹配仅针对已定义数据验证器的字段执行。

适用于

  • API网关
  • API服务,其中由于参数值众多,不能使用路由缓存
  • 仅确保在添加一批新端点后,路由不是性能下降的点

性能

基于matchitactix-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