WebFlux嵌套路由问题:子路径始终匹配顶层父路由
这个问题我之前排查过好几次,本质是对WebFlux的路由匹配规则理解不到位导致的,咱们一步步拆解:
核心匹配规则先搞清楚
WebFlux的路由匹配有两个关键逻辑:
- 按声明顺序匹配:定义在前面的路由会先被检查,第一个匹配上的路由就会处理请求(除非你主动传递请求给下一个路由)。
- 路径模式遵循Ant风格:
?匹配单个字符;*匹配任意非/的字符;**匹配任意字符(包括/,也就是所有子路径);
- 无方法限制则匹配所有HTTP方法:如果路由没指定
GET()/POST()这类方法谓词,它会接收任何请求方法的请求。
你的问题大概率是这两个原因之一
1. 顶层路由用了/api/person/**路径模式
如果你的顶层路由代码类似这样:
.route(RequestPredicates.path("/api/person/**"), req -> ServerResponse.ok().bodyValue("顶层路由响应"))
那/api/person/**这个模式会匹配所有以/api/person开头的路径(包括/api/person/1、/api/person/2/detail等),再加上没有限定请求方法,自然不管你用GET、POST还是PUT,请求都会被这个顶层路由截胡。
2. 嵌套路由中顶层处理函数没传递请求
要是你用了嵌套路由的写法,但顶层处理函数没有调用ServerRequest.next()传递请求,那请求匹配到顶层后就直接返回了,根本轮不到子路由。比如:
.path("/api/person", builder -> { // 这个顶层处理函数会直接响应请求,不会往下传递 builder.route(req -> ServerResponse.ok().bodyValue("顶层路由")); // 子路由永远不会被匹配到 builder.GET("/{id}", handler::getPersonById); })
(注:这里如果顶层路由的路径是/api/person本身,/api/person/1其实不会匹配它,但如果顶层路由在嵌套里用了/**路径,就会出现这种情况)
对应的解决办法
修正路径模式
把顶层路由的路径改成精确匹配的/api/person(不带**),这样它只会匹配/api/person和/api/person/(WebFlux默认开启matchTrailingSlash,允许末尾带斜杠),不会影响/api/person/1这类子路径的请求。
给顶层路由限定请求方法
比如只让顶层路由处理GET请求的/api/person:
.GET("/api/person", handler::listAllPersons)
这样其他方法的请求不会匹配它,/api/person/1这类子路径也不会触发这个路由。
前置处理时记得传递请求
如果顶层路由是用来做前置校验(比如token验证),一定要调用req.next()让请求继续往下匹配子路由:
.path("/api/person", builder -> { builder.route(req -> { // 这里写你的前置逻辑,比如校验用户权限 return req.next(); // 关键:把请求传递给后续的子路由 }); builder.GET("/{id}", handler::getPersonById); })
调整路由声明顺序
把更具体的路由(比如/api/person/{id})放在更通用的路由(比如/api/person)前面,这样具体的路由会先被匹配到:
return route() .GET("/api/person/{id}", handler::getPersonById) .GET("/api/person", handler::listAllPersons) .build();
内容的提问来源于stack exchange,提问作者Jan Testowy

