您的位置:时间博客>优词记>后端只有一条路由:聊聊我的自定义 Dispatcher 设计

后端只有一条路由:聊聊我的自定义 Dispatcher 设计

前两篇聊了背单词小程序「优词记 Pro」的整体架构和请求层封装,今天说说后端一个比较激进的设计:整个项目的路由文件只有一行

路由文件的痛

常规做法是每个接口注册一条路由。项目小的时候没问题,接口一多,路由文件就变成几百行的流水账:改个接口要同时动路由和控制器,命名风格慢慢漂移,review 时还得对着路由表找实现。既然我的接口 URL 本来就有强规律,为什么不让规律本身当路由?

于是全站只留一条通配路由,所有请求交给一个 Dispatcher 统一调度:

Router::addRoute(['GET','POST','PUT','DELETE'], '/{name:.+}', Dispatcher::class . '@handle');

三条约定替代整张路由表

约定一:URL 前缀分端。/admin/* 走管理端控制器目录,/user/* 走小程序端,/common/* 两端通用。不同端的认证策略也随前缀确定——管理端 JWT 有效期 7 天,小程序端 365 天,通用接口两种身份都放行。

约定二:HTTP 方法映射方法前缀。GET → get*,POST → create*,PUT → update*,DELETE → delete*。语义直接编码在方法名里,看到 createOrder 就知道它只接受 POST。

约定三:URL 段转驼峰拼方法名。kebab-case 的 URL 段转成 camelCase 后匹配控制器和方法,比如 GET /admin/user/list-page 会命中 User::getListPage()。找不到控制器时还有一次目录归约兜底:Foo\Bar 未命中就回退找 Foo\Bar\Index

请求命中
GET /admin/user/list-pageAdminPort\User::getListPage()
POST /user/collectionUserPort\Collection::create()
DELETE /admin/advertAdminPort\Advert::delete()

新增一个接口,只需要在对应目录放好控制器、按前缀命名方法,路由自动就通了,git diff 里只有一个文件。

认证和权限也挂在约定上

Dispatcher 找到目标方法后,先过认证再执行。默认全部接口要求登录,例外用 #[NoNeedLogin] 注解显式声明;需要细粒度权限的方法加 #[Permission(['manage-advert-add'])],由注解在调度时统一校验。权限、日志这些横切逻辑都收敛在调度层,业务控制器保持干净。

代价与取舍

约定路由不是免费的。两点代价说在前面:一是新人要先学约定,不看文档很难从 URL 直接反查代码位置,所以约定必须写进 README 并且从不破例;二是灵活性受限,比如当前实现不允许向方法传位置参数,多余的 URL 段直接 404——这是有意为之,宁可严格也不要歧义。对单人或小团队项目,用这点学习成本换掉整张路由表的维护成本,我认为很值。

产品本体是个背单词小程序,微信搜「优词记 Pro」可以体验。明天写写这套后端更「离经叛道」的部分:不写 migration,直接从数据库 schema 反向生成 Entity 和 Model 代码,感兴趣的可以关注。


转载请注明本文标题和链接:《 后端只有一条路由:聊聊我的自定义 Dispatcher 设计

相关推荐

网友评论 0

未登陆 表情
Ctrl+Enter快速提交