修复 Spring Boot 3.2 和 springdoc 2.2 的 Swagger UI 无法加载问题
2025-05-05 07:47:58
解决 Spring Boot 3.2.10 与 springdoc-openapi 2.2.0 下 Swagger UI 无法加载 (No static resource swagger-ui/index.html)
不少哥们儿升级到 Spring Boot 3.2.10 和 springdoc-openapi-starter-webflux-ui 2.2.0 之后,发现 Swagger UI 刷不出来了,浏览器控制台或者后台日志里杵着个明晃晃的错误:org.springframework.web.servlet.resource.NoResourceFoundException: No static resource swagger-ui/index.html.
。这感觉就像准备开车出门,结果发现车轱辘不见了。别急,这事儿能解决。
你的 pom.xml
依赖大概是这样:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.2.10</version>
<relativePath />
</parent>
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-starter-webflux-ui</artifactId>
<version>2.2.0</version>
<exclusions>
<exclusion>
<groupId>org.yaml</groupId>
<artifactId>snakeyaml</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
Swagger 配置可能长这样:
@Configuration
public class SwaggerConfig {
@Value("${Host:}")
private String configUrl;
@Bean
public OpenAPI OpenApi() {
Contact contact = new Contact();
contact.setName("Team ");
contact.setEmail("email.com");
OpenAPI openAPI = new OpenAPI();
if (StringUtils.isNotEmpty(configUrl)) {
openAPI.addServersItem(
new Server().url(configUrl));
}
openAPI.info(new Info().title(" Scheduler API")
.description("To schedulejobs").version("0.0.1-SNAPSHOT")
.contact(contact)
);
return openAPI;
}
}
遇到这问题,心里大概率会嘀咕:“版本都挺新的,怎么就不行了呢?”
二、抽丝剥茧:问题成因分析
No static resource swagger-ui/index.html
这个错误直截了当,意思就是 Spring Boot 找不到 swagger-ui/index.html
这个静态文件。Swagger UI 的界面是由一堆 HTML, CSS, JavaScript 静态文件组成的。springdoc-openapi-starter-webflux-ui
这个依赖包,会把这些静态文件打进你的应用,并通过 Spring WebFlux 的静态资源处理器机制暴露出来。
问题可能出在以下几个方面:
- 静态资源路径配置问题 :
springdoc-openapi
默认会将 Swagger UI 的资源文件映射到/webjars/swagger-ui/
目录下,并提供一个方便访问的路径,通常是/swagger-ui.html
(它会重定向到index.html
) 或者直接访问/swagger-ui/index.html
。如果这个映射关系因为某些配置出了岔子,那自然就找不到了。 - Spring Security 拦截 :如果你的项目里用了 Spring Security,它老人家可是个尽职的门卫。默认情况下,它可能会把访问
/swagger-ui/**
或相关API文档路径(如/v3/api-docs/**
)的请求给拦下来,因为它觉得这些请求没“票”(未认证)。 - WebFlux 静态资源处理器配置冲突或缺失 :Spring Boot WebFlux 对静态资源有一套自动配置。但如果你自定义了
WebFluxConfigurer
并重写了addResourceHandlers
方法,又不小心覆盖或未正确配置 Swagger UI 的资源路径,就可能导致这个问题。 - 项目上下文路径 (Context Path) 设置 :如果你的应用设置了
server.servlet.context-path
(对传统 Servlet 应用) 或spring.webflux.base-path
(对 WebFlux 应用),那么访问 Swagger UI 的基础 URL 会发生变化。虽然报错信息是内部找不到资源,但也可能是因为组合出来的最终访问路径不正确,或者内部解析时也受到了这个 base-path 的影响。 - 依赖冲突或版本不兼容 :虽然 Spring Boot 3.2.10 和 springdoc-openapi 2.2.0 通常是好搭档,但复杂的项目依赖关系偶尔也会导致意想不到的火花。比如,你可能无意中引入了不同版本的 Webjars 或者 Servlet API 相关的依赖,造成了冲突。
那个 snakeyaml
的排除,通常是为了解决特定版本 snakeyaml
的安全漏洞,或者与 Spring Boot 管理的 snakeyaml
版本冲突。一般来说,这个排除本身不太可能直接导致静态资源找不到,除非 springdoc-openapi
的某个深层逻辑在特定情况下因为缺少了某个期望的 snakeyaml
版本而行为异常 (概率较低)。
三、对症下药:解决方案逐个击破
知道了可能的原因,我们就可以挨个试试看。
方案一:确认 Spring Doc UI 路径配置
springdoc-openapi
提供了一些配置属性来控制 Swagger UI 的行为,其中最关键的是 UI 路径。
-
原理和作用 :
springdoc.swagger-ui.path
属性可以自定义 Swagger UI 页面的访问路径。springdoc-openapi-starter-webflux-ui
默认会把 Swagger UI 页面注册在/swagger-ui.html
,它会重定向到实际的index.html
。所以,/swagger-ui/index.html
是核心的资源文件路径。 -
操作步骤 :
在你的application.properties
或application.yml
文件中检查或显式设置这个路径。对于
application.properties
:# 默认情况下,这个配置可以不写,springdoc会自动配置 # 如果你发现访问 /swagger-ui.html 没用,或者想换个路径,可以试试明确指定 # springdoc.swagger-ui.path=/swagger-ui.html # 或者你想让API文档路径也统一管理 (可选) # springdoc.api-docs.path=/v3/api-docs
如果你在用
application.yml
:springdoc: swagger-ui: # path: /swagger-ui.html # 同样, 默认可不写 api-docs: # path: /v3/api-docs
一般情况,这个属性保持默认就好。出问题时,可以尝试访问
/swagger-ui.html
看看是否重定向。如果连/swagger-ui.html
都404,那问题可能更深层。 -
额外建议 :
确保你访问的是正确的路径。如果应用有 context-path (比如/myapp
),那么 Swagger UI 的完整路径应该是http://localhost:8080/myapp/swagger-ui.html
。
方案二:配置 Spring Security 放行 Swagger 相关路径
这是最常见的原因之一,特别是当项目集成了 Spring Security 时。
-
原理和作用 :
Spring Security 会保护应用的所有端点。你需要明确告诉它,哪些路径是不需要身份验证就能访问的,比如 Swagger UI 界面本身和它获取 API 定义的路径 (/v3/api-docs
等)。 -
代码示例 (使用
SecurityFilterChain
) :
Spring Boot 3.x 推荐使用基于组件的SecurityFilterChain
bean 配置。import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity; import org.springframework.security.config.web.server.ServerHttpSecurity; import org.springframework.security.web.server.SecurityWebFilterChain; @Configuration @EnableWebFluxSecurity // 如果你用了响应式安全 public class SecurityConfig { // Swagger UI 静态资源路径 private static final String[] SWAGGER_UI_RESOURCES = { "/swagger-ui.html", "/swagger-ui/**", "/v3/api-docs/**", // OpenAPI 规范 JSON/YAML 文件的路径 "/webjars/swagger-ui/**" // Swagger UI 自身的静态资源 }; @Bean public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) { http .authorizeExchange(exchanges -> exchanges .pathMatchers(SWAGGER_UI_RESOURCES).permitAll() // 放行 Swagger UI 相关路径 .pathMatchers("/public/**").permitAll() // 举例:其他公开路径 .anyExchange().authenticated() // 其他所有请求都需要认证 ) .httpBasic(ServerHttpSecurity.HttpBasicSpec::disable) // 如果不用 HTTP Basic .csrf(ServerHttpSecurity.CsrfSpec::disable); // WebFlux下CSRF通常也需要针对性处理,此处为简化 return http.build(); } }
注意 :
@EnableWebFluxSecurity
是用于 WebFlux 应用的。如果你错误地在一个 MVC 项目里用了springdoc-openapi-starter-webflux-ui
并配置了 WebFlux Security, 这本身就是个问题。确保你的项目类型和依赖选择一致。如果你是MVC项目,应该用springdoc-openapi-starter-webmvc-ui
和@EnableWebSecurity
。 -
安全建议 :
- 生产环境中,不建议完全公开 Swagger UI。最好是将其置于某种形式的认证保护之下,或者仅在开发 (dev) 和测试 (test) 环境中启用。
- 可以通过 Spring Profiles (
@Profile("dev")
) 来只在特定环境加载上述安全配置或 Swagger 本身的配置。
-
进阶使用技巧 :
对于更细致的控制,你可以将SWAGGER_UI_RESOURCES
数组中的路径配置在application.properties/yml
中,然后在SecurityConfig
中读取这些配置,这样修改路径时就不用改 Java 代码了。
方案三:检查 WebFlux 静态资源处理器配置
如果你自定义了 WebFluxConfigurer
,可能会影响默认的静态资源处理。
-
原理和作用 :
Spring Boot WebFlux 会自动配置静态资源服务。它会从一些预定义的 classpath 位置(如classpath:/static/
,classpath:/public/
,classpath:/resources/
,classpath:/META-INF/resources/
)以及 Webjars (如classpath:/META-INF/resources/webjars/
) 加载静态内容。springdoc-openapi-ui
包将 Swagger UI 静态文件打包为 Webjars 资源。如果你的自定义配置没有正确地包含或代理 Webjars 的处理器,或者覆盖了默认的路径匹配规则,Swagger UI 的静态文件就可能访问不到了。 -
操作步骤/代码示例 :
如果你确实需要自定义WebFluxConfigurer
,确保不要破坏 Webjars 的处理。大多数情况下,你根本不需要自定义addResourceHandlers
。如果一定要,可以参考如下(但这只是确保基础的静态资源和Webjars工作,通常Spring Boot自动配置做得更好):// import org.springframework.context.annotation.Configuration; // import org.springframework.web.reactive.config.ResourceHandlerRegistry; // import org.springframework.web.reactive.config.WebFluxConfigurer; // @Configuration // public class CustomWebFluxConfig implements WebFluxConfigurer { // @Override // public void addResourceHandlers(ResourceHandlerRegistry registry) { // // 这是Spring Boot通常会做的一部分,确保webjars可以访问 // registry.addResourceHandler("/webjars/**") // .addResourceLocations("classpath:/META-INF/resources/webjars/"); // // 如果你还有其他自定义的静态资源目录 // registry.addResourceHandler("/static/**") // .addResourceLocations("classpath:/static/"); // // 非常重要:除非你知道自己在做什么,否则不要随便覆盖或完全自定义 addResourceHandlers // // Spring Boot 的自动配置通常已经足够好,并且能正确处理 springdoc-openapi 的 UI 资源。 // // 如果添加了 @EnableWebFlux 注解,则必须自己配置所有东西,包括这里。 // } // }
强烈建议 :移除不必要的
WebFluxConfigurer
实现,尤其是那种仅仅是为了一个简单配置而全盘接管addResourceHandlers
的情况。同时,检查是否在配置类上使用了@EnableWebFlux
注解。这个注解会完全禁用 Spring Boot 对 WebFlux 的自动配置。如果你用了它,那你就得自己负责配置静态资源、消息转换器等所有东西。 -
额外建议 :
如果移除了@EnableWebFlux
注解(如果你之前有的话)或自定义的WebFluxConfigurer
,很多因自动配置被禁用而产生的问题(包括静态资源问题)往往能迎刃而解。
方案四:核查应用上下文路径
如果你设置了应用的根路径 (context path 或 base path),访问 URL 自然需要带上这个前缀。
-
原理和作用 :
spring.webflux.base-path=/your-app
(针对 WebFlux) 或者server.servlet.context-path=/your-app
(更多是传统 MVC 应用,但在某些混合场景下或因习惯可能也会用) 会改变你应用所有端点的基础URL。Swagger UI 的访问路径也会基于这个新的根路径。 -
操作步骤 :
检查application.properties
或application.yml
:For
application.properties
:# 如果你的应用是纯 WebFlux spring.webflux.base-path=/api-gateway # 假设你的基础路径是 /api-gateway # server.servlet.context-path=/my-cool-app # 通常在Spring Boot 3 WebFlux项目中不直接使用这个来设置应用根路径
如果设置了
spring.webflux.base-path=/api-gateway
,那么你的 Swagger UI 应该通过http://localhost:8080/api-gateway/swagger-ui.html
来访问。
确认你的访问 URL 是否正确。 -
额外建议 :
统一配置。如果项目是纯 WebFlux,优先使用spring.webflux.base-path
。这个配置对springdoc-openapi
的路径解析也有影响。
方案五:检查是否有 @EnableWebFlux
注解捣乱
这是一个容易被忽视的点。
-
原理和作用 :
@EnableWebFlux
注解的作用是导入WebFluxConfigurationSupport
,这会让你完全接管 WebFlux 的配置,Spring Boot 的 WebFlux 自动配置会失效。这意味着很多便利的默认设置,比如静态资源处理、Content Negotiation、编解码器等,都需要你手动配置。springdoc-openapi-ui
的自动配置也依赖于 Spring Boot 的 WebFlux 自动配置。 -
操作步骤 :
全局搜索你的项目代码,看看有没有哪个@Configuration
类上加了@EnableWebFlux
。// @Configuration // @EnableWebFlux // <--- 如果存在这个注解,尝试移除它 // public class SomeWebConfig { // // ... 可能有一些你自定义的 WebFlux 配置 // }
如果找到了,并且你不是非用它不可(比如为了实现一些非常底层的、自动配置无法满足的定制),尝试将它注释掉或删除。Spring Boot 的自动配置在大多数场景下都足够强大和灵活。
-
额外建议 :
绝大多数 Spring Boot 应用不需要@EnableWebFlux
。Spring Boot 的条件化自动配置 (spring-boot-autoconfigure
) 旨在开箱即用。只有当你明确知道为什么需要完全控制,并且愿意承担手动配置所有相关组件的责任时,才使用它。移除它之后,确保测试所有 WebFlux 相关功能是否依然按预期工作。
方案六:依赖版本和冲突排查
虽然较为少见,但检查依赖总是没错的。
-
原理和作用 :
Maven 或 Gradle 的依赖解析可能引入不兼容的库版本。springdoc-openapi-starter-webflux-ui
自身依赖于特定版本的swagger-ui
Webjar。如果项目中其他依赖引入了另一个版本,或者与 Spring Boot 管理的某些基础 Web 库冲突,可能会出问题。 -
操作步骤 :
使用 Maven/Gradle 的依赖分析工具。
对于 Maven:mvn dependency:tree
仔细查看输出,特别关注与
swagger-ui
、webjars-locator-core
(如果springdoc
用到的话) 或者 Spring Framework WebFlux 相关的库。确保springdoc-openapi-starter-webflux-ui
的版本2.2.0
和 Spring Boot3.2.10
是兼容的(它们通常是)。springdoc
官方文档会说明其版本与 Spring Boot 版本的对应关系。2.2.0
是为 Spring Boot 3.x 设计的,这点应该没问题。 -
额外建议 :
考虑使用 Spring Boot 的 BOM (Bill of Materials) 来管理依赖版本,它可以帮助统一许多常用库的版本。springdoc-openapi
通常不包含在 Spring Boot 的主 BOM 里,所以你需要自己确保它的版本和 Boot 版本兼容。
排查这种问题,有点像侦探探案。通常从最可疑的“嫌犯”(Spring Security、路径配置)入手,逐步扩大排查范围。每做一个调整后,记得重启应用并清空浏览器缓存再试,避免旧缓存捣乱。一般情况下,通过上述几个方案的排查和调整,swagger-ui/index.html
应该就能乖乖地出现了。