环境:Spring6.1.11
1. Bug介绍
这是一个关于Spring 函数式接口的问题。
Spring Web MVC 包含 WebMvc.fn,是一种轻量级的函数式编程模型,其中函数用于路由和处理请求,并且设计了不可变性的契约。它是基于注解(@RequestMapping)的编程模型的替代方案,但在其他方面与 DispatcherServlet 相同。有关函数式接口详细,查看下面的文章:
你以为只有Controller一种接口定义方式?详解Web函数式接口
接下来将详细介绍bug的复现的过程
1.1 路由接口定义
环境采用SpringBoot3.2.8该版本对应的Spring版本是6.1.11。
路由定义
RouterFunction<ServerResponse> userRouter(UserHandler handler) {return route().path("/routers/users", builder -> builder.GET("/{id}", accept(MediaType.TEXT_HTML), handler::findById)).build() ;}
路由处理函数
public class UserHandler {public ServerResponse findById(ServerRequest request) {User user = new User(Long.valueOf(request.pathVariable("id")),request.param("name").orElse(null)) ;return ServerResponse.ok().body(user) ;}}
请求测试

没有问题
1.2 bug复现
接下来,我们只需要在配置文件中进行如下的servlet path配置问题就会出现了
spring:mvc:servlet:path: /api
该配置会给DispatcherServlet访问路径添加/api前缀。
如上配置后,当你再次访问上面的/routers/users/*接口时,将会出现如下错误

说明:该错误的出现是只针对的上面那种嵌套路由,其它普通的路由则不会有这样的问题。
2. 给Spring官方提交issue

问题提出后作者给出了回复

意思是确认问题,同时你可以通过下面的配置进行临时代替
server:servlet:context-path: /api
通过配置上下文的方式确实可以解决。
最终该问题在spring6.1.12版本中修复,当前我使用的最新springboot3.2.8最高支持的spring是6.1.11。所以我们可以通过如下方式进行替换为最新的Spring版本
<properties><spring-framework.version>6.1.12</spring-framework.version></properties>
在maven项目中的pom.xml中配置如上的属性即可替换当前springboot依赖的Spring版本。
错误原因
这种嵌套路由在进行RequestPredicate路径匹配时,构建请求路径时,不知道怎么想的直接抛出异常(整个过程就不细说了,看下最终构建上下文时的代码):
Spring6.1.11版本中(包括之前)
public abstract class ServletRequestPathUtils {private static final class ServletRequestPath implements RequestPath {// 这里的contextPath = /routers/users/6666 (这时候并没有包括我们的/api前缀)public RequestPath modifyContextPath(String contextPath) {// 毫不犹豫,直接抛出异常throw new UnsupportedOperationException();}}}
Spring6.1.12版本中修复
private static final class ServletRequestPath implements RequestPath {public RequestPath modifyContextPath(String contextPath) {// 将当前配置的servletPathPrefix拼接到当前的请求上下文路径// 也就是将/api拼接到 当前请求的/routers/users/6666中return new ServletRequestPath(this.pathElements.withContextPath(contextPath));}}
项目中如果你也遇到这样的问题,你可以按照上面的方式进行修复,要么就是不要使用这种嵌套路由无非就是多写两行代码也没什么关系。
以上是本篇文章的全部内容,如对你有帮助帮忙点赞+转发+收藏
推荐文章
SpringBoot错误使用拦截器导致系统奔溃,发生OOM错误
强大!SpringBoot通过这3个注解监测Controller接口
强大!必须掌握!Spring Security这些技巧你知道吗?
玩转Redis!非常强大的Redisson分布式集合,少写60%代码
SpringBoot3.2开始Controller参数验证@Validated新功能



