koa路由中间件库的选用问题

刚好最近开发tigo的时候遇到了一个关于koa的重要问题,总结一篇文章出来分享一下。

koa这个著名的中间件我就不多说了,这一次我重点写的内容如标题所述,是中间件库的选用问题。

@koa/router

这是一个最默认的库了,一般写koa的后端都会以这个作为路由。得益于它背后是koa官方,知名度高,使用它的项目以及愿意给这一中间件做贡献的开发者都不少。

虽然官方没有规定路由中间件一定要写成某种样子,但是得益于其高知名度与良好的设计,@koa/router给整个社区提供了一个路由中间件的基本规范,社区另外的一些中间件在主要接口的调用上都基本与它没有什么区别。

它最强大的地方在于,基于path-to-regexp,它可以对路径进行非常灵活的、基于正则的动态匹配,可编程性、灵活性非常高。

但是同时这也是它最大的问题,由于其动态匹配设计模式简单,没有考虑优化因素,以至于对比Fastify之类以性能为著称的框架或者其他路由中间件时,@koa/router的表现比较糟糕。

koa-rapid-router

@koa/router的性能问题不单单是QPS这一块的问题,因为每一个请求都需要一定的时间去处理,所以从请求到达Server到业务逻辑执行之间的Latency会比较高,对这个性能指标比较敏感的业务也不太适合使用@koa/router。

在搜索引擎里我找到了其他开发者宣传的koa-rapid-router,它同样支持正则匹配,通过对实现进行改良,这个库相对@koa/router性能有极其显著的提升,表现接近Fastify。

这个中间件不难找到,但是出人意料的是它star很少,项目活跃度也比较低,看一眼issue区,我个人觉得使用过程中遇到了问题应该很难得到其开发者/贡献者的帮助。

但从性能角度来说这是一个很优秀的库,同时它也兼顾了@koa/router的灵活,因而一开始我个人写tigo选择的是它。路由中间件在达到一定稳定程度之后基本不需要很频繁的更新,稳定性足够强,即使一两年不维护也问题不大。

随着我个人的使用,这个中间件的不完善不断暴露出来,它存在下面这两个致命问题:

  • 致命地使用了path.resolve拼接路径的base和传入值
  • 动态匹配实现有致命缺陷

细说这两个问题,第一个问题并不是只会导致Windows用户用不了,path.resolve会导致路径里包含的相对路径被解析,可能会引起一些业务逻辑错误甚至是安全问题。

这个修改起来很简单,我在@pwp-app这个scope下的版本已经修改过了。

这个中间件最大的问题主要是第二个。虽然它文档提到支持贪婪匹配末尾,但是在实际的代码实现上,开发者忽略了这一点的测试,且路由实际的实现并没有做到。

举个例子,我有一个路径是:

1
/api/v1/path/to/file/static/test.html

根据官方的文档,我写一个如下的贪婪匹配:

1
/api/v1/path/to/file/{name?any}

由于路径本身是根据斜杠去切片的,实现里表示贪婪匹配的标志变量没有什么实际意义,代码实现本身看上去并没有真正支持贪婪匹配,这会导致上面那个路径直接404。

上述两个致命问题会给业务逻辑的编写带来不小的影响,尤其是贪婪匹配这一块,非常成问题,它直接扼杀了取一段路径在业务逻辑里进行二次处理的可能。

处于上面这个原因,我抛弃了这个库。这个问题修肯定是可以修的,但是整个路由中间件的实现大致看下来,这需要投入不少时间。由于这个仓库的代码本身也比较抽象,我个人目前不愿意投入时间去补这个问题。

koa-tree-router

这个库是我在Bing上搜索“koa high performence router”出现的第一个搜索结果,它基于一个go那边的路由,利用trie结构存储路由信息,以此大幅提升性能,Benchmark中,这个中间件的性能是@koa/router的10倍。

它不支持基于正则的动态路由匹配,只支持简单路由匹配,对比上面两个中间件,它的灵活性更低。

但是这并不影响你使用它,我个人认为它能覆盖大部分使用场景,在正常的设计下,它提供的简单匹配+贪婪匹配足够使用。即使你的路由需要设计得比较复杂,我个人认为这个问题也可以在业务逻辑上解决。

目前来看这个库开发者在维护上还可以,此前这个开发者也参与了svg-captcha的维护,我个人觉得还算靠谱。

其实koajs这个组织下面也有一个类似的库,叫koa-trie-router,但是这个库两年没更新了,稳定性未知。如果你对灵活性有更高的要求,可以尝试一下这个库。

它使用了Routington做动态匹配,这个包是支持正则的,这可能会导致它性能相对偏弱。

koa-joi-router

这个是在@koa/router的基础上引入了joi对功能进行增强,活跃度较高,适合对路由有进阶复杂需求的朋友。

当然,性能方面自然是要舍弃一些的……

小结

因为大部分开发者都是直接用@koa/router,不会过多关注它的性能问题。

对于一般场景我个人推荐用koa-tree-router,如果它不能满足需求,可以再换用@koa/router。在路由这方面我个人的思想是尽可能让路由趋于简单,性能优先,很多逻辑是可以过了路由再实现的。

日后如果我用koa-tree-router的时候遇到了雷,我应该会另外开一个文章说一说。