NestJS注册API抛出BadRequestException时出现异常问题排查
注册API重复邮箱校验异常排查方案
1. 先查find()查询的返回值处理
很多开发者都踩过这个坑:
- 要是用JPA的
findByEmail(),无匹配数据时会返回null,但如果是异步查询(比如加了@Async注解或用了CompletableFuture),直接用if(user != null)判断等于白搭——你拿到的是Future对象,不是实际的查询结果。 - 还要确认查询条件是否生效:比如数据库里的邮箱字段大小写敏感,前端传小写、数据库存大写,
find()就查不到重复数据,导致不会抛出异常;或者字段名拼写错误,比如把email写成mail。
修正示例:
// 错误写法:直接判断异步Future对象 if(userRepository.findByEmailAsync(email) != null) { throw new BadRequestException("邮箱已注册"); } // 正确写法:等待异步结果后再判断 Optional<User> existingUser = userRepository.findByEmail(email).join(); if(existingUser.isPresent()) { throw new BadRequestException("邮箱已注册"); }
2. 确认全局异常处理器是否能接住BadRequestException
抛出异常却没返回预期的400响应,大概率是异常没被正确处理:
- 检查项目中有没有带
@RestControllerAdvice注解的全局异常处理类,里面是否有专门处理BadRequestException的方法,并且正确设置了HttpStatus.BAD_REQUEST状态码。 - 避免更通用的异常处理器(比如捕获
RuntimeException的方法)抢占优先级,导致BadRequestException被当成通用异常处理,返回错误的状态码。
正确的异常处理器片段:
@RestControllerAdvice public class GlobalExceptionHandler { @ExceptionHandler(BadRequestException.class) public ResponseEntity<ErrorResponse> handleBadRequest(BadRequestException ex) { ErrorResponse error = new ErrorResponse(HttpStatus.BAD_REQUEST.value(), ex.getMessage()); return new ResponseEntity<>(error, HttpStatus.BAD_REQUEST); } }
3. 检查BadRequestException的定义
如果是自定义异常类,没继承RuntimeException的话,Spring MVC不会自动捕获,直接返回500错误:
- 要么把自定义异常改成继承
RuntimeException,要么直接用Spring自带的ResponseStatusException,省去自定义异常和处理器的配置:
if(existingUser.isPresent()) { throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "邮箱已注册"); }
4. 排查数据库层面的问题
- 看看当前方法有没有加
@Transactional注解,要是事务传播行为设置不当,可能导致查询读不到刚提交的邮箱数据,或者事务未提交就执行查询,导致重复校验失效。 - 给邮箱字段添加唯一约束作为兜底,就算代码校验漏了,数据库也会抛出约束异常,记得也要处理这个异常(比如捕获
SQLIntegrityConstraintViolationException)。
5. 对比正常项目的差异点
既然另一个项目的同款逻辑没问题,直接对比以下内容:
- 依赖版本:Spring Boot、Spring Data JPA的版本是否一致,不同版本的
find()方法行为可能存在差异。 - 异常处理配置:两个项目的全局异常处理器逻辑是否完全一致。
- 查询方法写法:比如一个返回
Optional<User>,另一个返回User,对应的判断逻辑自然不同。
内容的提问来源于stack exchange,提问作者Chaitanya S
相关产品推荐
相关产品推荐

