Spring Boot 1.5升级3.4后AJAX请求/set-preferences路由异常
问题分析与解决方案
问题背景
将Spring Boot应用从1.5升级至3.4,同时Java从8升级到21后,发送至/set-preferences/的AJAX POST请求无法到达控制器,被当作静态资源处理并抛出NoResourceFoundException,但控制器和AJAX代码未做任何修改。
错误日志
org.springframework.web.servlet.resource.NoResourceFoundException: No static resource set-preferences. : [org.springframework.web.servlet.resource.ResourceHttpRequestHandler.handleRequest(ResourceHttpRequestHandler.java:585), org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter.handle(HttpRequestHandlerAdapter.java:52), org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1088), org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:978), org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1014), org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:914), jakarta.servlet.http.HttpServlet.service(HttpServlet.java:547), org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:885), jakarta.servlet.http.HttpServlet.service(HttpServlet.java:614),
控制器代码
@Controller public class HomeController { @RequestMapping(value = "/set-preferences", method = RequestMethod.POST) public String LoginHome(@RequestBody Request request, Model model) { UserPreference preference = userPreferenceJsonUtils.convertToObject( request.getStrUserPreference(), UserPreference.class); setAdditionalUserPreference(preference); setResponseMessage(preference, model); model.addAttribute("userPreferences", gfeJsonUtils.convertToJson(preference)); model.addAttribute("User", getUsername()); return "homePage"; } }
AJAX代码
var fnAjaxCallToSaveUserPreference = function(Request) { $.ajax({ type: "POST", url: "set-preferences/", contentType: "application/json", async: false, data: JSON.stringify(Request), cache: false, beforeSend: function() { $('.loadingImageOpacBg').show(); }, success: function(data) { if (data !== "") { $("#" + "headerId").html(data); } }, error: function(xhr, status, error) { console.error("AJAX Error:", error); } }); }
问题解答
1. 为何升级后请求无法到达控制器?
核心原因是路径匹配规则的变更:
- Spring Boot 1.5默认使用
AntPathMatcher,允许忽略URL尾斜杠,/set-preferences和/set-preferences/会被视为同一路径。 - Spring Boot 3.x默认使用
PathPatternParser,启用严格路径匹配,严格区分尾斜杠。你的AJAX请求URL是set-preferences/(带尾斜杠),但控制器映射的是/set-preferences(不带尾斜杠),因此DispatcherServlet无法找到对应的控制器方法,转而尝试匹配静态资源,最终抛出NoResourceFoundException。
2. 是否与Spring Boot 3.x的Spring MVC变更有关?
是的,这直接关联Spring MVC的核心变更:
Spring Framework 6.x(Spring Boot 3.x依赖)对路径匹配系统进行了重构,默认采用PathPatternParser替代旧的AntPathMatcher,后者默认允许尾斜杠匹配,而前者默认严格匹配所有路径字符,包括尾斜杠。这是Spring MVC在3.x版本中的重大行为变化。
3. 额外调试步骤
- 启用MVC调试日志:在
application.properties中添加logging.level.org.springframework.web.servlet=DEBUG,查看DispatcherServlet对请求路径的匹配过程,确认请求到底被哪个处理器接收。 - 测试无尾斜杠的请求:手动发送POST请求到
/set-preferences(不带尾斜杠),验证是否能到达控制器,快速确认尾斜杠的问题。 - 检查组件扫描范围:确保
HomeController所在的包被@SpringBootApplication的组件扫描覆盖,避免控制器未被注册到Spring容器。 - 排查拦截器/过滤器:检查升级后新增或变更的拦截器、过滤器(比如Spring Security配置),确认是否有逻辑修改了请求路径或拦截了请求。
- 验证请求体解析:虽然当前错误是静态资源未找到,但可测试请求体是否能被正确解析(Spring 3.x依赖的Jackson版本与1.5差异较大,可能影响
@RequestBody的处理)。
解决方案
方案1:修改AJAX请求URL(推荐)
将AJAX中的URL修改为不带尾斜杠:
url: "set-preferences"
这是最符合Spring MVC 3.x严格匹配规则的做法,避免后续路径匹配问题。
方案2:配置Spring MVC允许尾斜杠匹配
如果无法修改前端代码,可在application.properties中配置:
# 切换回旧的AntPathMatcher(兼容旧行为) spring.mvc.pathmatch.matching-strategy=ant-path-matcher
或者,若想保留PathPatternParser并启用尾斜杠匹配:
spring.mvc.pathmatch.trailing-slash-match=true
内容的提问来源于stack exchange,提问作者user30002040
相关产品推荐
相关产品推荐

