欢迎光临
我们一直在努力

Knife4j:doc.html 白屏、报 NoSuchMethodError?别动版本,给全局异常处理器加个 @Hidden 就好

排查了一整天,最后只加了一个注解。问 AI 查文章,得到的答案不是劝你升级降级版本,就是让你改一堆配置文件,绕了一大圈,其实一个注解就能解决。

背景

有时候项目迭代升级后,文档页面突然白屏,控制台还冒出 NoSuchMethodError 之类的报错。很多人第一反应是“版本不兼容”,于是想着升级 springdoc、降级 Spring Boot……可生产环境里版本往往是定死的,动一发牵全身,根本不敢随便改。

我前两天也踩了这个坑,折腾很久发现:根本不用动版本,只要给全局异常处理器加一个 @Hidden 注解,问题就解决了。

一、环境信息

维度版本
Spring Boot 3.5.x(Spring Framework 6.2.x,Java 17)
Knife4j knife4j-openapi3-jakarta-spring-boot-starter 4.1.0(内置 springdoc 1.7.0)
注解体系 OpenAPI 3(io.swagger.v3.oas.annotations)

二、问题现象

2.1 页面表现

访问 doc.html,页面白屏/报错,右上角提示 “Knife4j 文档请求异常”,接口列表加载不出来,效果如下:

2.2 前端控制台(F12)报错

打开浏览器 F12 看 Network 与 Console,能看到这样一串报错:

v3/api-docs:1 Failed to load resource: the server responded with a status of 500 ()
app.30e79dc0.js:1 Error: Request failed with status code 500
at e.exports (chunk-vendors.d59642c5.js:2:679693)
at e.exports (chunk-vendors.d59642c5.js:2:1298909)
at XMLHttpRequest.y (chunk-vendors.d59642c5.js:2:1868675)

关键信息就两条:

  • /v3/api-docs 返回 500:文档页加载的核心数据请求失败了;
  • app.30e79dc0.js 报 Request failed with status code 500:前端拿不到合法数据,自然渲染不出文档页;

2.3 后端控制台报错

真正的原因在后端,控制台报错如下:

jakarta.servlet.ServletException: Handler dispatch failed:
java.lang.NoSuchMethodError:
'void org.springframework.web.method.ControllerAdviceBean.<init>(java.lang.Object)'
Caused by: java.lang.NoSuchMethodError:
'void org.springframework.web.method.ControllerAdviceBean.<init>(java.lang.Object)'
at org.springdoc.core.service.GenericResponseService…

三、关键复现:一个注解让文档恢复

项目里有这样一个全局异常处理器:

@RestControllerAdvice
public class GlobalExceptionAdvice {

@ExceptionHandler
public ResponseEntity<?> handleWoNiuHealthException(WoNiuHealthException e) {
e.printStackTrace();
return ResponseEntity.status(500)
.body(Map.of("code", 500, "message", e.getMessage()));
}

@ExceptionHandler
public ResponseEntity<?> handleException(Exception e) {
e.printStackTrace();
return ResponseEntity.status(500)
.body(Map.of("code", 500, "message", e.getMessage()));
}
}

实测:

状态现象
去掉 @Hidden doc.html 白屏,/v3/api-docs 报 NoSuchMethodError
加上 @Hidden 文档恢复正常

四、根因说明(为什么不是版本不兼容?)

很多人在看到 NoSuchMethodError 时会下意识认为是 springdoc 版本太老,不兼容 Spring Framework 6.2.x,于是急着去升级依赖。但这次的问题其实不是版本兼容性问题,而是 Springdoc 内部扫描机制触发了对 ControllerAdviceBean 构造方法的调用,而这个调用在特定条件下才会出问题。

关键点在于:

  • Springdoc 在生成 OpenAPI 规范时,会扫描所有标注了 @RestControllerAdvice 的类,并尝试将它们包装成 ControllerAdviceBean 进行处理。

  • 在 Spring Framework 6.2.x 中,ControllerAdviceBean 的构造方法签名发生了变化,而 springdoc 1.7.0 在某些场景下(比如遇到 ResponseEntity<?> 这种需要复杂类型解析的情况)会调用旧版本的构造方法,从而抛出 NoSuchMethodError。

  • 这个报错是 Error 而不是 Exception,所以 @ExceptionHandler(Exception e) 根本接不住它,只能眼睁睁看着它往上抛。

  • 结论:问题不在于“版本不兼容”,而在于 Springdoc 在扫描全局异常处理器时,触发了不兼容的方法调用。只要让 Springdoc 跳过对全局异常处理器的扫描,就能完美规避这个问题,而不需要动任何版本。

    五、我的解决方法(什么都不用改,只加一个注解)

    import io.swagger.v3.oas.annotations.Hidden;

    @RestControllerAdvice
    @Hidden // 让 Springdoc 忽略该类
    public class GlobalExceptionAdvice {
    // … 异常处理方法
    }

    就这一个注解。

    原理很简单:@Hidden 通知 Springdoc 完全忽略这个类,不再扫描它、不做 Advice 包装、不解析返回类型,那串触发 NoSuchMethodError 的代码直接不执行,/v3/api-docs 正常生成,doc.html 立刻恢复。

    六、为什么我推荐它,而不是升级/降级版本?

    方案成本风险
    升级/降级 Spring Boot 或 springdoc 高(需回归测试、协调团队) 高(可能引入新问题)
    加 @Hidden 注解 极低(一行代码) 极低(只影响文档扫描)

    可以说,这是当前成本和风险都最低的解法,也是我最想分享给同样踩坑的朋友的做法。

    赞(0)
    未经允许不得转载:171主机测评 » Knife4j:doc.html 白屏、报 NoSuchMethodError?别动版本,给全局异常处理器加个 @Hidden 就好
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址