01 正则编译式路由匹配引擎


文档摘要

01 正则编译式路由匹配引擎 本节摘要:OpenWork 的服务端不用任何 Web 框架,却承担了整个产品的 HTTP 中枢。它是怎么做到的?靠一套自研的正则编译式路由引擎——把路径里的 编译成正则,顺序匹配。本节讲清这套路由引擎的工作原理:路由怎么定义、 怎么编译成正则、请求怎么匹配与提取参数,以及「为什么不用框架」的工程理由。 一、不用框架的中枢 先点出一个反直觉的事实:OpenWork 的服务端不用任何流行的 Web 框架。它是自研的极简 HTTP 中枢,用很少的代码承担了路由、鉴权、引擎反代、能力管理等所有职责。 为什么不用框架?三个理由: 透明:自己写的路由,每一步都看得见、改得动,没有框架的「黑盒」。 轻量:不引入框架的体积和抽象,启动快、依赖少。

01 正则编译式路由匹配引擎

本节摘要:OpenWork 的服务端不用任何 Web 框架,却承担了整个产品的 HTTP 中枢。它是怎么做到的?靠一套自研的正则编译式路由引擎——把路径里的 :param 编译成正则,顺序匹配。本节讲清这套路由引擎的工作原理:路由怎么定义、:param 怎么编译成正则、请求怎么匹配与提取参数,以及「为什么不用框架」的工程理由。

一、不用框架的中枢

先点出一个反直觉的事实:OpenWork 的服务端不用任何流行的 Web 框架。它是自研的极简 HTTP 中枢,用很少的代码承担了路由、鉴权、引擎反代、能力管理等所有职责。

为什么不用框架?三个理由:

  • 透明:自己写的路由,每一步都看得见、改得动,没有框架的「黑盒」。
  • 轻量:不引入框架的体积和抽象,启动快、依赖少。
  • 够用:OpenWork 的路由需求不复杂(就是路径匹配 + 参数提取),不值得为这个引入整个框架。

这种「极简自研」是 OpenWork 服务端设计的核心哲学——能用很少代码做的事,就不引入复杂依赖。

二、路由的定义

一条路由由几部分组成:

路由 = { method: "GET" | "POST" | ..., path: "/workspace/:id/session", // 含 :param 的路径 auth: AuthMode, // 鉴权模式(第 04 节) handler: 处理函数 }

其中 path 里的 :param(如 :id)是「路径参数占位」——它匹配路径里的某段,并提取出来作为参数。

三、:param 编译成正则

路由引擎的核心动作是把 path 编译成正则。过程大致是:

原始 path: /workspace/:id/session │ ▼ 把 :param 替换成捕获组 正则: ^/workspace/([^/]+)/session$ │ ▼ 同时记录参数名顺序 参数名: [id] │ ▼ 存储编译后的正则 + 参数名

关键点:

  • :param 被替换成 ([^/]+)——匹配「非斜杠的一或多字符」,这正是「一段路径」的语义。
  • ^...$ 锚定整条路径,保证精确匹配(不会前缀误匹配)。
  • 编译是一次性的——路由注册时编译,之后每次请求直接用编译好的正则,不用重编。

💡 编译一次的红利:和 OpenCode 工具系统的「编译一次校验器」(OpenCode 教程第 5 章)同理——正则编译只跟路由定义有关,不跟具体请求有关。注册时编译一次,之后匹配几乎零成本。

四、请求的匹配

请求来时,路由引擎顺序匹配:

请求: GET /workspace/abc123/session │ ▼ 遍历所有路由,按顺序试匹配 │ ├─ 路由1 正则不匹配 ──► 跳过 ├─ 路由2 正则匹配! ──► 命中 │ │ │ ▼ 从匹配结果提取参数 │ match[1] = "abc123" → 参数 id = "abc123" │ │ │ ▼ 解码参数(encodeURIComponent 还原) │ id = decode("abc123") │ ▼ 用提取的参数调 handler handler({ id: "abc123", ... })

提取参数的细节:正则匹配后,捕获组的内容按顺序对应参数名,再 decodeURIComponent 还原(因为路径里可能被 URL 编码过)。

五、顺序匹配的意义

路由引擎是顺序匹配(从前往后找第一个匹配的)。这意味着:

  • 路由注册顺序影响匹配——更具体的路由应该排在更通用的前面。
  • 第一个匹配的胜出,后面的不再试。

⚠️ 注册顺序的注意:虽然 OpenWork 内部路由注册顺序是设计好的(你一般不用管),但理解「顺序匹配」有助于排查「为什么请求匹配到了错的路由」——可能是顺序问题。

六、为什么这套简单方案够用

你可能会问:这么简单的路由(正则匹配),够用吗?对 OpenWork 来说够用,因为:

  • 它的路由需求就是「路径匹配 + 参数提取」,没有复杂的(如正则约束、可选参数、通配中间段)。
  • 复杂的逻辑(鉴权、反代、能力声明)不在路由层,而在 handler 和中间件里。
  • 简单方案 = 少 bug = 好维护。

如果未来需求变复杂(需要更强大的路由),再增强或引入框架也不迟——但现在,简单方案正合适。这是「按需复杂度」的工程智慧。

七、本节要点回顾

  1. 不用框架:服务端自研极简 HTTP 中枢,透明、轻量、够用。
  2. 路由定义:method + path(含 :param)+ auth + handler。
  3. :param 编译成正则:替换成 ([^/]+) 捕获组,锚定整条路径,注册时编译一次。
  4. 顺序匹配:从前往后找第一个匹配,提取参数解码。
  5. 顺序影响匹配:具体的排前面;第一个匹配胜出。
  6. 简单方案够用:需求就是路径匹配+参数提取,复杂逻辑在别处——按需复杂度。

路由匹配讲清了,下一节讲路由之上「服务端能干什么」的自述——能力声明契约。


发布者: 作者: 灏天文库 转发
评论区 (0)
U