为何Spring抛出404异常却返回401状态码响应?
问题描述
我创建了一个新的Java Spring应用,并添加了一个包含单个方法的控制器:
@RestController public class MyController { @GetMapping("/test") public String test() { throw new ResponseStatusException(HttpStatus.NOT_FOUND); } }
当我发送GET /test请求时,收到无响应体的401状态码响应。但在Spring应用的标准输出中,我看到如下日志:
WARN 36 --- [nio-8080-exec-2] .w.s.m.a.ResponseStatusExceptionResolver : Resolved [org.springframework.web.server.ResponseStatusException: 404 NOT_FOUND]
请问为何会返回401而非预期的404?
原因分析与解决方案
这种矛盾现象的核心原因是请求的响应状态码被后续的拦截/过滤逻辑覆盖,最常见的场景和解决方法如下:
1. Spring Security 默认拦截(最普遍情况)
如果你的项目引入了spring-boot-starter-security依赖,Spring Security会默认对所有请求启用认证拦截:
- 尽管日志显示控制器的404异常已被处理,但Security的过滤器链可能在后续环节修改了响应状态码;或者你的请求未通过认证,但因配置疏漏意外进入了控制器,最终Security强制将响应改为401。
解决方法:
在Security配置类中显式允许/test路径的匿名访问:
@Configuration @EnableWebSecurity public class SecurityConfig { @Bean public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { http.authorizeHttpRequests(authConfig -> authConfig .requestMatchers("/test").permitAll() // 放行/test路径,无需认证 .anyRequest().authenticated() ); return http.build(); } }
配置完成后,请求会正常到达控制器,返回预期的404状态码。
2. 自定义过滤器/拦截器修改响应状态码
如果项目中存在自定义的Filter或HandlerInterceptor,这些组件可能在ResponseStatusExceptionResolver处理完404异常后,重新修改了HttpServletResponse的状态码为401。
排查方法:
- 检查项目中所有实现
Filter接口或继承HandlerInterceptor的类,查看是否存在修改响应状态码的逻辑; - 临时禁用这些自定义组件,重新测试请求,验证是否恢复正常404响应。
3. 全局异常处理器配置错误
若项目中使用了@RestControllerAdvice实现全局异常处理,可能存在错误逻辑将ResponseStatusException(404)转换为401响应。
排查方法:
检查全局异常处理器的代码,确保没有错误映射404异常到401状态码的逻辑。
内容的提问来源于stack exchange,提问作者Vaks
相关产品推荐
相关产品推荐

