如何在Springdoc OpenAPI中针对特定端点隐藏全局异常处理器的403响应
问题背景
现有一个Spring Boot应用,异常处理逻辑通过通用@ControllerAdvice和多个@ExceptionHandler实现,示例如下:
@ControllerAdvice public class CustomExceptionHandler extends ResponseEntityExceptionHandler { @ResponseStatus(HttpStatus.FORBIDDEN) // 403 @ExceptionHandler(AccessDeniedCustomException.class) public ResponseEntity<Object> handleAccessDeniedException(Exception ex, WebRequest request) { ... } @ResponseStatus(HttpStatus.NOT_FOUND) // 404 @ExceptionHandler(NotFoundCustomException.class) public ResponseEntity<Object> handleNotFoundException(Exception ex, WebRequest request) { ... } }
当前配置下,Springdoc OpenAPI生成的OpenAPI YAML文件会为所有端点附带403、404的响应定义。
已知在异常处理方法上添加@Hidden注解会全局移除该响应码,不符合需求,需要实现仅对部分特定端点隐藏403响应的效果。
实现方案
方案一:通过端点本地注解覆盖全局响应配置
Springdoc的响应配置优先级为:端点方法上声明的@ApiResponse > 全局通过@ControllerAdvice扫描生成的异常响应定义。
针对单个或少量需要隐藏403的端点,直接在端点方法上显式声明所有需要展示的响应码,不包含403即可覆盖全局配置。
示例:
@RestController public class DemoController { // 该端点需要隐藏403响应定义 @GetMapping("/public/content") @Operation( summary = "公开内容接口", responses = { @ApiResponse(responseCode = "200", description = "请求成功"), @ApiResponse(responseCode = "404", description = "资源不存在") // 未声明403响应,全局的403定义不会被合并到该端点的文档中 } ) public String getPublicContent() { return "content"; } }
方案二:自定义标记注解 + OpenAPI全局过滤器批量处理
如果需要批量为大量端点隐藏403响应,逐字逐句写@ApiResponse配置过于冗余,可以通过自定义注解配合OpenAPI扩展能力实现批量处理:
- 定义自定义标记注解,用于标记需要隐藏403的端点或整个控制器类:
@Target({ElementType.METHOD, ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) public @interface IgnoreForbiddenDoc { } - 实现
OpenApiCustomizer接口,在OpenAPI文档生成完成前,遍历所有路径配置,对打了标记注解的端点,从响应列表中移除403定义:@Component public class ForbiddenDocExcludeCustomizer implements OpenApiCustomizer { @Autowired private RequestMappingHandlerMapping requestMappingHandlerMapping; @Override public void customise(OpenAPI openApi) { // 遍历所有接口映射,匹配带标记注解的端点 requestMappingHandlerMapping.getHandlerMethods().forEach((mappingInfo, handlerMethod) -> { // 检查方法或所属类上是否存在标记注解 boolean needExclude = handlerMethod.hasMethodAnnotation(IgnoreForbiddenDoc.class) || handlerMethod.getBeanType().isAnnotationPresent(IgnoreForbiddenDoc.class); if (!needExclude) { return; } // 获取匹配的OpenAPI路径项 String path = mappingInfo.getPatternValues().stream().findFirst().orElse(null); PathItem pathItem = openApi.getPaths().get(path); if (pathItem == null) { return; } // 移除该路径下所有操作的403响应定义 pathItem.readOperations().forEach(operation -> { operation.getResponses().remove("403"); }); }); } }
注意事项
- 两种方案都不会影响未标记端点的403响应文档展示,完全避免了在全局异常处理器上加
@Hidden导致的全局屏蔽问题 - 方案一适合少量定制化端点场景,配置轻量无额外代码逻辑;如果遇到Springdoc版本差异导致全局403仍然被自动合并到端点文档的情况,直接使用方案二即可100%达成效果
- 方案二适合批量标记的场景,只需要在需要隐藏403的端点或控制器类上加
@IgnoreForbiddenDoc注解即可,维护成本更低
内容的提问来源于stack exchange,提问作者Svichkarev Anatoly
相关产品推荐
相关产品推荐

