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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.18 16:24:54