01 正则编译式路由匹配引擎 本节摘要:OpenWork 的服务端不用任何 Web 框架,却承担了整个产品的 HTTP 中枢。它是怎么做到的?靠一套自研的正则编译式路由引擎——把路径里的 编译成正则,顺序匹配。本节讲清这套路由引擎的工作原理:路由怎么定义、 怎么编译成正则、请求怎么匹配与提取参数,以及「为什么不用框架」的工程理由。 一、不用框架的中枢 先点出一个反直觉的事实:OpenWork 的服务端不用任何流行的 Web 框架。它是自研的极简 HTTP 中枢,用很少的代码承担了路由、鉴权、引擎反代、能力管理等所有职责。 为什么不用框架?三个理由: 透明:自己写的路由,每一步都看得见、改得动,没有框架的「黑盒」。 轻量:不引入框架的体积和抽象,启动快、依赖少。
本节摘要:OpenWork 的服务端不用任何 Web 框架,却承担了整个产品的 HTTP 中枢。它是怎么做到的?靠一套自研的正则编译式路由引擎——把路径里的
:param编译成正则,顺序匹配。本节讲清这套路由引擎的工作原理:路由怎么定义、:param怎么编译成正则、请求怎么匹配与提取参数,以及「为什么不用框架」的工程理由。
先点出一个反直觉的事实:OpenWork 的服务端不用任何流行的 Web 框架。它是自研的极简 HTTP 中枢,用很少的代码承担了路由、鉴权、引擎反代、能力管理等所有职责。
为什么不用框架?三个理由:
这种「极简自研」是 OpenWork 服务端设计的核心哲学——能用很少代码做的事,就不引入复杂依赖。
一条路由由几部分组成:
路由 = { method: "GET" | "POST" | ..., path: "/workspace/:id/session", // 含 :param 的路径 auth: AuthMode, // 鉴权模式(第 04 节) handler: 处理函数 }
其中 path 里的 :param(如 :id)是「路径参数占位」——它匹配路径里的某段,并提取出来作为参数。
路由引擎的核心动作是把 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 来说够用,因为:
如果未来需求变复杂(需要更强大的路由),再增强或引入框架也不迟——但现在,简单方案正合适。这是「按需复杂度」的工程智慧。
([^/]+) 捕获组,锚定整条路径,注册时编译一次。路由匹配讲清了,下一节讲路由之上「服务端能干什么」的自述——能力声明契约。