c -> true 导致异常返回 404 问题排查

最近在新开一个项目,在新建基础架构的时候遇到了一个很有意思的问题:

  • 接口正常访问时返回 200
  • Controller 中人为制造异常后
  • 后端日志明确打印了异常
  • 但前端(Apifox)收到的却是 404
  • 理论上应该返回 500

最终排查发现:

根因是 Spring Boot 全局路径前缀配置污染了系统内置的 /error 路由。

这个问题非常具有迷惑性,记录一下完整排查过程。

一、问题现象

Controller层制造异常,用于测试异常处理 :

java 复制代码
int a = 1 / 0;

二、后端日志

java 复制代码
java.lang.ArithmeticException: / by zero

完整调用链中可以看到:

java 复制代码
Servlet.service() for servlet [dispatcherServlet]
threw exception

说明:

  • Controller 已经执行
  • 异常已经抛出
  • Spring MVC 已经捕获异常

按正常逻辑:

应该返回:

java 复制代码
500 Internal Server Error

但实际上:

Apifox 返回:

java 复制代码
404 Not Found

三、第一次怀疑方向

一开始怀疑:

1. AOP 吞异常

因为项目里有:

java 复制代码
@Around
public Object around(ProceedingJoinPoint point)

很多项目会写成:

java 复制代码
try {
    return point.proceed();
} catch (Exception e) {

}
return null;

这种会导致:

  • Spring 找不到返回视图
  • 最终变成 404

但检查后发现:AOP 没问题

2. 全局异常处理器

怀疑:

java 复制代码
@ControllerAdvice

或者:

java 复制代码
@ExceptionHandler

吞掉异常

检查后排除

四、真正的问题

项目中有如下配置:

java 复制代码
@Configuration
public class WebConfig implements WebMvcConfigurer {

    @Override
    public void configurePathMatch(PathMatchConfigurer configurer) {

        // 为所有 Controller 添加 /api 前缀
        configurer.addPathPrefix("/api", c -> true);
    }
}

问题就出在:c -> true

五、问题原理分析

这段代码的意思是:

给所有 Controller 都加 /api 前缀。

注意:

这里的"所有 Controller"不仅仅包括:

  • 自己写的 Controller

还包括:

  • Spring Boot 内置 Controller
  • BasicErrorController
  • /error
  • actuator
  • swagger 等

六、为什么正常接口还能返回 200?

正常情况下请求流程:

DispatcherServlet

-> Controller

-> return AjaxResult.success()

-> 200

因为没有异常:

  • 不会进入 /error
  • 所以一切正常

因此返回:200 OK

七、为什么异常时变成 404?

出现异常后,Spring MVC 流程:

DispatcherServlet

-> Controller 抛异常

-> 异常解析器

-> 转发到 /error

正常应该:

/error

-> BasicErrorController

-> 返回 500

但由于:

java 复制代码
addPathPrefix("/api", c -> true)

Spring 内置:

/error

也被加了前缀:

/api/error

现在问题就来了:

Spring Boot 默认真正注册的是:/error;不是/api/error

于是异常发生后:

/api/error

找不到。

最终:

404 Not Found

八、问题本质

这里的 404:并不是业务接口不存在;而是异常处理路由不存在

九、最终解决方案

不要给所有 Controller 都加前缀。

应该只给自己的业务 Controller 加。

修改为:

@Configuration

public class WebConfig implements WebMvcConfigurer {

@Override

public void configurePathMatch(PathMatchConfigurer configurer) {

configurer.addPathPrefix(

"/api",

c -> c.getPackageName().startsWith("com.bs.web.controller")

);

}

}

这样:

  • 自己业务 Controller:

    /api/xxx

  • Spring 系统 Controller:

    /error

不会受影响

总结

c -> true 这种全匹配不要随便使用,Spring Boot 的 /error一旦被污染各种诡异问题都会出现

相关推荐
en.en..5 小时前
C语言核心解析:#define与typedef本质区别
开发语言·c++·算法
2601_966949655 小时前
批量获取多只股票五档盘口的极简方案:QuantDash Python SDK 实战指南
开发语言·python·数据分析·pandas·量化交易·股票数据·quantdash
点心的游戏开发世界6 小时前
GDScript 入门笔记:目录
开发语言·笔记·游戏引擎·godot
洋不写bug6 小时前
二叉树(二) 常见基础操作解析|结点数、树高、查找结点、判断完全二叉树
java·开发语言·数据结构·完全二叉树·二叉树结点数·树高·查找结点
果果燕6 小时前
实习笔记(六)主机按钮状态上报完整流程
开发语言·c++·php
平头哥技术团队7 小时前
Day 16 | 用 ul、ol、li 一个标签,把散资料收成有序的技能清单页
开发语言·前端·html·html5
统计学小王子7 小时前
数学建模国赛倒计时 2 天 ——《统计模型精讲(广义线性模型 R 语言实例 + 分析)》
开发语言·数学建模·r语言
此冬歌咏7 小时前
自动化服务器运维监控系统(python+shell)
linux·运维·服务器·开发语言·python·自动化
Cx330❀7 小时前
【Linux网络】深入TCP协议:从滑动窗口到拥塞控制与性能优化全景解析
linux·开发语言·网络·tcp/ip·ai·性能优化·ai编程
“AI国潮设计-小江”7 小时前
【Python实战】SDXL精准控制“普宁英歌舞×星空蛋糕”IP落地,附核心Prompt与商用授权思路
开发语言·人工智能·python·prompt·aigc