You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.13 16:25:54