我最近将 Spring Boot 应用程序从版本 3.4.0 升级到 3.4.1,并遇到了 Spring Data REST 的问题。
在版本 3.4.0(以及所有之前的 3.x 版本)中,以下配置按预期工作:
spring.data.rest.base-path=/api
设置此属性后,我可以通过以下方式成功访问我的 REST API 资源: http://localhost:8080/api/todos
但是,升级到 Spring Boot 3.4.1 后,该配置不再起作用。尝试使用配置
spring.data.rest.base-path
访问 API 端点会导致 404 Not Found 错误。我怀疑可能与 Spring Boot DevTools 依赖项存在冲突,因为删除它可以解决问题。
环境
如何重现
我在此存储库中有一个可重现的示例
mvn clean spring-boot:run
curl -v http://localhost:8080/api/todos
您将收到 404 Not Found 错误。
观察到的行为
访问 API 端点会导致白标错误页面:
Whitelabel Error Page
This application has no explicit mapping for /error, so you are seeing this as a fallback.
There was an unexpected error (type=Not Found, status=404).
No static resource api/todos.
org.springframework.web.servlet.resource.NoResourceFoundException: No static resource api/todos.
at org.springframework.web.servlet.resource.ResourceHttpRequestHandler.handleRequest(ResourceHttpRequestHandler.java:585)
at org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter.handle(HttpRequestHandlerAdapter.java:52)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1088)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:978)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1014)
at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:903)
at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:564)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:885)
at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:658)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:195)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140)
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:51)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:164)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140)
at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:164)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140)
at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:164)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140)
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:164)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:167)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:90)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:483)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:115)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:93)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:344)
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:397)
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:63)
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:905)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1741)
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:52)
at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1190)
at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:63)
at java.base/java.lang.Thread.run(Thread.java:1575)
预期行为:
我期望获得成功响应,并显示 200 状态代码和以下输出:
{
"_embedded": {
"todos": []
},
"_links": {
"self": {
"href": "http://localhost:8080/api/todos?page=0&size=20"
},
"profile": {
"href": "http://localhost:8080/api/profile/todos"
}
},
"page": {
"size": 20,
"totalElements": 0,
"totalPages": 0,
"number": 0
}
}
与 DevTools 可能发生的冲突:
排除故障后,我发现删除 Spring Boot DevTools 依赖项可以解决该问题。例如:
<!--
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
-->
删除 DevTools 依赖项后,应用程序将成功运行。您可以访问端点 http://localhost:8080/api/todos,它会按预期返回 200 响应以及以下内容。
{
"_embedded": {
"todos": []
},
"_links": {
"self": {
"href": "http://localhost:8080/api/todos?page=0&size=20"
},
"profile": {
"href": "http://localhost:8080/api/profile/todos"
}
},
"page": {
"size": 20,
"totalElements": 0,
"totalPages": 0,
"number": 0
}
}
我尝试过的
spring.data.rest.base-path
属性更改的任何提及,但找不到任何相关内容。问题
spring.data.rest.base-path
属性的行为是否发生了变化?任何指导或解决方法将不胜感激!
我还将此作为 bug 提交给 Spring Boot 项目团队。
是的,该问题似乎是 2024 年 12 月 19 日发布的最新春季 3.4.1 中引入的错误。两种可能的解决方法是,
(参考:https://www.udemy.com/course/spring-hibernate-tutorial/learn/lecture/36836512#questions/22798063)