
Spring Boot 应用因上下文路径(context-path)配置不一致,导致请求无法正确路由至控制器,继而被错误地反复转发至根路径 /myContext/,最终引发 StackOverflowError。本文详解问题成因、修复步骤及关键配置要点。
spring boot 应用因上下文路径(context-path)配置不一致,导致请求无法正确路由至控制器,继而被错误地反复转发至根路径 `/mycontext/`,最终引发 `stackoverflowerror`。本文详解问题成因、修复步骤及关键配置要点。
该问题本质是 URL 路径映射失配 与 错误转发机制叠加 所致。从日志可见两个关键线索:
- No mapping for POST /myContext/:DispatcherServlet 尝试匹配 /myContext/(而非 /myContext/api/v1/record/import),说明请求未进入 Spring MVC 的正常路由链;
- Forwarding to index + 无限递归调用 setAttribute() + doDispatch():表明某处配置(如前端控制器、静态资源处理或自定义 ForwardConfiguration)在找不到匹配处理器时,将请求无条件转发至 /myContext/,而该路径又再次触发相同逻辑,形成死循环。
根本原因在于:客户端请求路径、Spring Boot 运行时上下文路径、控制器 @RequestMapping 三者未对齐。
✅ 正确的路径结构应为:
客户端请求 URL → http://localhost:8080/{context-path}/api/v1/record/import
Spring Boot 配置 context-path → server.servlet.context-path=/myContext
控制器映射 → @RequestMapping("/api/v1") → 实际生效路径 = /myContext/api/v1
但当前 Postman 发送的是 POST localhost:8080/myContext/api/v1/record/import,而 server.servlet.context-path 未正确启用,导致 Spring Boot 实际以默认根上下文 / 启动。此时 DispatcherServlet 只识别 /api/v1/record/import,却收到带 /myContext/ 前缀的请求,自然无法匹配——进而落入兜底转发逻辑,触发循环。
? 解决方案(三步统一配置)
1. 显式声明上下文路径(必做)
在 application.properties 中添加:
server.servlet.context-path=/myContext
⚠️ 注意:/myContext 必须以 / 开头,且不能包含尾部斜杠(如 /myContext/ 是错误的)。
2. 确保构建产物名称一致(可选但推荐)
若使用 Maven 构建 WAR 包并部署到外部 Tomcat,则需在 pom.xml 中指定 finalName,使生成的 WAR 文件名为 myContext.war:
<build><finalname>myContext</finalname><plugins><plugin><groupid>org.springframework.boot</groupid><artifactid>spring-boot-maven-plugin</artifactid></plugin></plugins></build>
? 对于内嵌 Tomcat(默认模式),此步非必需,但保持命名一致性可避免混淆。
3. 客户端请求路径修正
Postman 中应发送:
POST http://localhost:8080/myContext/api/v1/record/import
✅ 此时 /myContext 由 Spring Boot 自动剥离(因 context-path 已配置),剩余路径 /api/v1/record/import 才会精准匹配 @RestController 的 @RequestMapping("/api/v1")。
❌ 常见误区排查
| 错误做法 | 后果 | 正解 |
|---|---|---|
| 仅改 application.properties 但未重启应用 | 配置未生效 | 修改后必须重启 Spring Boot 进程 |
| 在 @RequestMapping 中重复写 /myContext | 路径变为 /myContext/myContext/api/v1 | Controller 只写业务路径,上下文由 server.servlet.context-path 统一管理 |
| 使用 @SpringBootApplication(scanBasePackages = "...") 但忽略包扫描范围 | Controller 未被加载 | 确保 MyController 在主启动类同包或子包下,或显式指定扫描路径 |
? 验证是否修复
启动后访问 http://localhost:8080/myContext/actuator/mappings(需引入 spring-boot-starter-actuator),搜索 /record/import,应看到类似输出:
{
"handler": "public org.springframework.http.ResponseEntity<java.lang.string> com.example.MyController.importRecord(...)",
"predicate": "{[/api/v1/record/import],methods=[POST],consumes=[application/json],produces=[application/json]}"
}</java.lang.string>
这表明映射已正确注册。
? 总结
无限循环并非代码逻辑错误,而是 环境配置与请求约定错位 引发的典型路由故障。核心原则是:server.servlet.context-path 是唯一可信的上下文入口,所有外部请求和内部映射均需以此为基准对齐。配置完成后,无需修改 Controller 层代码,即可彻底解决 StackOverflowError 和 PageNotFound 循环问题。










