Spring Boot抛出异常后控制台与客户端均无异常信息显示问题
问题:Spring Boot表单认证API中运行时异常无日志输出且客户端无法接收异常信息
我正在开发一个带表单认证的用户API,仅权限用户可访问。当前遇到的问题是:触发运行时异常时,控制台不打印异常栈信息,客户端也收不到异常详情。
单元测试通过,且log.error("Cannot find user with username: {}", username);能正常打印,说明throw语句已执行,推测问题和Spring框架相关。尝试过用@ControllerAdvice+@ExceptionHandler处理,仅能返回ResponseEntity,但控制台还是没有异常输出。
相关代码片段
服务层代码
@Service @AllArgsConstructor @Slf4j public class AppUserService { private AppUserRepository repository; public AppUser getUserByUsername(String username) { if (!repository.existsByUsername(username)) { log.error("Cannot find user with username: {}", username); throw new UserNotFoundException("User with username '" + username + "' not found"); } log.info("Fetching user with username: {}", username); return repository.findAppUserByUsername(username); } }
单元测试代码
@ExtendWith(MockitoExtension.class) class AppUserServiceTest { @Mock private AppUserRepository repository; private AppUserService underTest; @BeforeEach @SuppressWarnings("resource") void setUp() { openMocks(this); underTest = new AppUserService(repository); } // [...] @Test void cannotGetUserByUsernameWhenUsernameIsNotInDB() { // given given(repository.existsByUsername(any())).willReturn(false); String username = "Adam"; // when // then assertThatThrownBy(() -> underTest.getUserByUsername(username)) .isInstanceOf(UserNotFoundException.class) .hasMessageContaining("User with username '" + username + "' not found"); then(repository).shouldHaveNoMoreInteractions(); } // [...] }
仓库层代码
@Repository public interface AppUserRepository extends JpaRepository<AppUser, UUID> { AppUser findAppUserByUsername(String username); // [...] }
自定义异常类
@ResponseStatus(HttpStatus.NOT_FOUND) public class UserNotFoundException extends RuntimeException { public UserNotFoundException(String message) { super(message); } }
配置文件
application.properties
# info info.application.name=@name@ info.application.version=@version@ info.application.description=@description@ info.application.jdk=@java.version@ info.application.groupId=@groupId@ # DB spring.datasource.url=jdbc:postgresql://localhost:5432/auth spring.datasource.username=postgres spring.datasource.password=1234 spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.PostgreSQLDialect spring.jpa.properties.hibernate.format_sql=true spring.jpa.hibernate.ddl-auto=create # server server.error.include-message=always server.error.include-binding-errors=always
pom.xml
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>3.0.2</version> <relativePath/> </parent> <groupId>com.xdavide9</groupId> <artifactId>Spring-Auth</artifactId> <version>0.0.1-SNAPSHOT</version> <name>Spring-Auth</name> <description>Form based authentication made with Spring Boot.</description> <properties> <java.version>17</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency> <dependency> <groupId>org.thymeleaf.extras</groupId> <artifactId>thymeleaf-extras-springsecurity5</artifactId> <version>3.1.1.RELEASE</version> </dependency> <dependency> <groupId>org.postgresql</groupId> <artifactId>postgresql</artifactId> <scope>runtime</scope> </dependency> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-test</artifactId> <scope>test</scope> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <configuration> <excludes> <exclude> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </exclude> </excludes> </configuration> </plugin> </plugins> </build> </project>
解决方案
1. 控制台无异常日志的修复
Spring Boot默认会处理未捕获的异常,但不会自动打印异常栈到控制台,有两种修复方式:
方式一:在全局异常处理器中手动记录日志
修改@ControllerAdvice类,在处理异常时打印完整栈信息:
@ControllerAdvice @Slf4j public class GlobalExceptionHandler { @ExceptionHandler(UserNotFoundException.class) public ResponseEntity<String> handleUserNotFound(UserNotFoundException ex) { log.error("用户查询异常", ex); return new ResponseEntity<>(ex.getMessage(), HttpStatus.NOT_FOUND); } }
方式二:调整日志配置
在application.properties中添加日志级别配置,确保异常相关日志能输出:
# 开启web模块和自定义包的DEBUG级别日志 logging.level.org.springframework.web=DEBUG logging.level.com.xdavide9=DEBUG
2. 客户端无法接收异常信息的修复
确保Spring Security不拦截异常响应
如果使用了Spring Security,需检查配置是否覆盖了全局异常处理。可以禁用API路径的默认异常处理,让@ControllerAdvice生效:
@Configuration @EnableWebSecurity public class SecurityConfig { @Bean public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { http // ...其他认证授权配置 .exceptionHandling(handler -> handler.defaultAuthenticationEntryPointFor(null, new AntPathRequestMatcher("/api/**")) ); return http.build(); } }
开启异常栈信息返回(可选)
如果需要客户端获取完整异常栈,可在配置中添加:
server.error.include-stacktrace=always
注:生产环境不建议开启此配置,避免泄露敏感信息。
内容的提问来源于stack exchange,提问作者Davide
相关产品推荐
相关产品推荐

