OpenAPI错误展示不同请求方法状态码问题咨询
问题描述
控制器代码
@GetMapping("/employees/{id}") Employee getEmployee(@PathVariable Long id) { return employeeService.getEmployee(id); } @GetMapping("/employees") List<Employee> getAllEmployees() { return employeeService.getEmployees(); } ... @ResponseBody @ResponseStatus(value = HttpStatus.NOT_FOUND, reason = "Employee not found") @ExceptionHandler(EmployeeNotFoundException.class) public ResponseEntity<ErrorData> employeeNotFoundHandler(EmployeeNotFoundException ex) { log.error(ex.getMessage()); ErrorData errorData = new ErrorData(ex.getMessage()); return new ResponseEntity<>(errorData, HttpStatus.NOT_FOUND); } // For post requests @ResponseBody @ResponseStatus(value = HttpStatus.UNPROCESSABLE_ENTITY, reason = "Some message") @ExceptionHandler(SomeException.class) ResponseEntity<ErrorData> someExceptionHandler(SomeException ex) { log.error(ex.getMessage()); ErrorData errorData = new ErrorData(ex.getMessage()); return new ResponseEntity<>(errorData, HttpStatus.UNPROCESSABLE_ENTITY); }
疑问
查看OpenAPI输出时发现,GET /employees被标注为可能返回200、404或422,GET /employees/{id}同样被标注为这三个状态码。但按预期,GET /employees应仅返回200,GET /employees/{id}应返回200或404,请问这是为何?
原因分析与解决方案
原因
你定义的这两个@ExceptionHandler方法默认会作用于当前控制器(或全局控制器通知类,如果用@RestControllerAdvice标注)下的所有请求处理方法。OpenAPI生成工具(比如SpringDoc)会自动扫描这些异常处理器,把对应的响应状态码关联到每一个接口上,不管该接口实际会不会抛出对应异常。
比如处理SomeException的方法返回422状态码,即便GET /employees和GET /employees/{id}根本不会抛出这个异常,OpenAPI还是会把422加到这两个接口的响应列表里。
解决方案
有几种方式可以修正:
缩小异常处理器的作用范围
- 如果异常处理器写在全局
@RestControllerAdvice类中,可以通过basePackages、assignableTypes等属性指定只作用于特定控制器(比如处理POST请求的控制器):@RestControllerAdvice(assignableTypes = {PostEmployeeController.class}) public class GlobalExceptionHandler { @ExceptionHandler(SomeException.class) ResponseEntity<ErrorData> someExceptionHandler(SomeException ex) { log.error(ex.getMessage()); ErrorData errorData = new ErrorData(ex.getMessage()); return new ResponseEntity<>(errorData, HttpStatus.UNPROCESSABLE_ENTITY); } } - 也可以把
SomeException的处理器移到专门处理POST请求的控制器类中,避免影响GET接口。
- 如果异常处理器写在全局
手动为接口指定响应状态码
使用OpenAPI的@ApiResponses注解,明确指定每个接口的合法响应状态码,覆盖自动生成的结果:@GetMapping("/employees") @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "返回所有员工列表") }) List<Employee> getAllEmployees() { return employeeService.getEmployees(); } @GetMapping("/employees/{id}") @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "返回指定员工"), @ApiResponse(responseCode = "404", description = "员工不存在") }) Employee getEmployee(@PathVariable Long id) { return employeeService.getEmployee(id); }配置OpenAPI排除不需要的状态码
如果用SpringDoc,可以在配置类中针对特定路径或全局排除不必要的状态码:@Configuration public class SpringDocConfig { @Bean public OpenAPI customOpenAPI() { return new OpenAPI() .paths(new Paths() .addPathItem("/employees", new PathItem() .get(new Operation() .responses(new ApiResponses() .addApiResponse("200", new ApiResponse().description("请求成功")) ) ) ) .addPathItem("/employees/{id}", new PathItem() .get(new Operation() .responses(new ApiResponses() .addApiResponse("200", new ApiResponse().description("请求成功")) .addApiResponse("404", new ApiResponse().description("员工不存在")) ) ) ) ); } }
内容的提问来源于stack exchange,提问作者Islam Azab
相关产品推荐
相关产品推荐

