HTTP 请求分发与路由优先级
本章介绍 TioBootHttpRequestDispatcher 的请求分发流程与 DefaultHttpRequestRouter 的路由匹配规则。
请求链
域名与路径处理 → CORS 预检(启用且带 Origin / Access-Control-Request-Method)→ Session / 限流 → 请求上下文 → 校验与普通 before 拦截器 → 路由匹配 → doBeforeRoute → 业务处理 → after 拦截器与统计 → finally 释放上下文。
动态路由依次尝试普通 Handler、Groovy、Function、Controller。普通路由发现方法不匹配时,必须先让其他动态路由尝试匹配,全部未命中才生成 405;不存在普通路由方法冲突时,继续转发、静态资源和 404。不要在多个路由器中重复定义同一业务入口,以免兼容回退产生意外行为。
现有分支仍以响应是否为 null 判断是否继续。Handler 写入完成后必须返回明确响应,不能用 null 表示成功或业务失败。
方法匹配规则
router.get("/items", listHandler);
router.post("/items", createHandler);
router.add(HttpMethod.DELETE, "/items/{id}", deleteHandler);
- 优先查找显式请求方法;HEAD 没有显式处理器时尝试 GET;最后才查旧 ANY。
- 同一方法级别内,精确路径优先于通配符,通配符优先于模板。
- 通配符按较长前缀优先;长度相同时保留注册顺序。
/*和/**保持历史前缀匹配语义,不能把/*当作严格只匹配一层。 - 模板支持
{id}、{id:[0-9]+}与末尾连续可选段{id}?。多个模板都匹配时保留注册顺序。 (method, path)重复注册立即报错;旧add(path, handler)的同路径注册保持覆盖行为。
路由器使用注册时排序的不可变快照,匹配不保留无限增长的请求路径缓存,因此新增路由立即可见,不会因旧命中缓存继续进入已被更精确路径覆盖的 Handler。
匹配结果和参数
router.match(request) 返回 RouteMatch,包含 MATCHED / NOT_FOUND / METHOD_NOT_ALLOWED、RouteDefinition、路径参数和允许方法集合。默认路由器的匹配是纯查询,最终分发时才 match.apply(request) 注入路径参数;同名 query/body 参数不会覆盖 URL 路径参数。
resolve(request) 是兼容入口,成功时应用参数并返回 Handler,失败时返回 null;需要区分 404 与 405 时使用 match。第三方旧路由器由接口默认适配器调用原 resolve,其参数副作用仍由自身实现决定。
find(path) 保留旧精确/通配符 ANY 查询语义;方法路由不要用它查找。all() 返回只读的旧精确/通配符 ANY 视图;allRoutes() 返回完整的注册快照,包含方法、模板和 metadata。外部自定义路由器需要实现方法注册扩展,默认方法会明确抛出 UnsupportedOperationException,不会悄悄退化成 ANY。
405、HEAD、OPTIONS、CORS
- 已知路径但请求方法不支持:405,
Allow包含可用方法;有 GET 时增加 HEAD,自动协商增加 OPTIONS。 - HEAD 使用实际选中 GET/HEAD 的鉴权策略;响应编码保留 Content-Length,不发送内存体或文件体。流式/SSE 处理器应自行避免在 HEAD 路径开启持续写流。
- 已知方法路由的自动 OPTIONS:204 和 Allow;显式 OPTIONS 可以定义业务行为。
- 启用
server.http.response.cors.enable=true后,带 Origin 与 Access-Control-Request-Method 的 OPTIONS 按 CORS 预检处理,不进入业务鉴权;实际请求照常鉴权。预检使用框架 CORS 响应规则,Allow 提示不能替代实际方法校验。 - 未启用 CORS 时,不会自动添加允许跨域头。普通 OPTIONS 仍经过现有 before 拦截器,可能因既有认证策略被拒绝。
- 框架 405 为协议响应,未自动套用业务 JSON 格式。
拦截器与上下文
doBeforeHandler 保持在路由选择前。新增 doBeforeRoute 在匹配成功后、业务执行前调用;普通 Handler 提供 RouteMatch,其他动态路由传 null。返回响应会短路业务执行。现有 after 回调继续按模型匹配规则执行,不等同于“仅对成功执行过 before 的模型逆序回调”。
after 与统计执行期间 TioRequestContext 仍有效,最外层 finally 才释放;after 或统计抛错也会清理。异步任务必须显式传递用户 ID 等数据,不能在线程切换后读取请求线程上下文。
上下文前缀
server.context-path=/admin 时,外部 /admin/api/items 去掉前缀后按 /api/items 路由。现有实现不是对所有不带前缀请求强制拒绝的访问控制器;权限必须由鉴权与业务授权明确检查。
迁移和完整配置见 方法路由与业务鉴权,参数与错误响应见 Handler 契约。
