写在前面
有个项目使用springboot3.2、webflux
,发现一直使用的knife4j
开发的 swagger
增强不可用了。目前市面上很多组件对webflux
的支持非常有限,大部分是直接不支持。本文是记录在springboot3.2、webflux
下使用open api
加knife4j-ui
做集成的示例。
一、引入包
- 环境说明
openjdk 21
kotlin 1.9.20
gradle 8.5
implementation("org.springframework.boot:spring-boot-starter-webflux")
// 我用的 kotlin,如果是java 下面4个包不需要
implementation("com.fasterxml.jackson.module:jackson-module-kotlin")
implementation("io.projectreactor.kotlin:reactor-kotlin-extensions")
implementation("org.jetbrains.kotlin:kotlin-reflect")
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-reactor")
// spring open api 包支持
implementation("org.springdoc:springdoc-openapi-starter-webflux-ui:2.3.0")
// 第三方 knife4j对open api的ui支持(纯属比默认的api页面好看点,可以不要)
implementation("com.github.xiaoymin:knife4j-openapi3-ui:4.4.0")
// 我自己写的权限组件
implementation("io.github.liuchengts:spring-boot-webflux-auth-starter:1.0.0.3")
二、配置
- 配置
webflux open api
/**
* openApi 文档配置
*/
@Configuration
class WebFluxOpenApiConfig {
@Bean
fun openApi(@Value("\${springdoc.version}") appVersion: String?): GroupedOpenApi {
val packagedToMatch = arrayOf("com.lc.flow.controllers")// 你的api包
return GroupedOpenApi.builder().group("flow-v2-server") //名称
.addOpenApiCustomizer { openApi ->
openApi.info(
Info().title("flow-v2-server Api").version(appVersion)
)
}
.packagesToScan(*packagedToMatch)
.build()
}
}
- 配置
webflux-auth
@Configuration
class AuthConfiguration @Autowired constructor(
private val filterWhiteListService: FilterWhiteListService
) {
@PostConstruct
fun init() {
/**
* 匹配白名单
* 规则:
* 1、* 表示单级路由通配符
* 匹配成功后会进入下一级路由匹配;
* 匹配失败后会使用当前真实单级路由进行匹配;
* 当真实单级路由匹配失败后本方法返回匹配失败,匹配成功则进入前两种场景
* 2、** 表示多级路由通配符
* 匹配成功后会直接返回成功,跳过后面的所有匹配逻辑;
* 没有成功会进行 * 模式匹配
* 3、开头带 / 或不带 效果相同
*
* 注意:请忽略示例中的星号前后空格(与注释冲突,必须要空格)
* 例1: /a/b/c 等效 a/b/c
* 例2: /**/b/c 效果 ** 开头的全部放行,不会再验证 b/c 任意级路由任意字符
* 例3: /a/ * /c 效果 中间a和b中间的路由可以是任意字符
* 例4: /a/b/ * 效果 验证完/a/b 之后 后面的最后一级可以是任意字符
* 例5: /a/b/ ** 效果 验证完/a/b 之后 后面的可以是任意级路由任意字符
*
*/
filterWhiteListService.addWhiteList(
"/login",
"/login/**",
"/doc.html",
"/v3/api-docs/**",
"/v3/api-docs.yaml",
"/v3/api-docs/swagger-config",
"/swagger-ui.html",
"/swagger-ui/**",
"/swagger-resources",
"/swagger-resources/**",
"/configuration/ui",
"/configuration/security",
"/webjars/**"
)
}
}
- 配置
application.yml
(这种配置需要配置nginx
对open api
的代理)
server:
#配置代理,参考:https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#howto.webserver.use-behind-a-proxy-server
forward-headers-strategy: framework
# 配置 springdoc(open api)参考:https://springdoc.org/index.html#Introduction
springdoc:
version: '@springdoc.version@'
api-docs:
enabled: true
swagger-ui:
enabled: true
参考文档: springdoc
到这里,本地启动就完成了:
- 访问
knife4j
好看些的页面:http://localhost:8080/doc.html
- 访问原始页面:
http://localhost:8080/swagger-ui.html
注意:
通过nginx
代理了这个springboot
使用的不是 location / {}
,会发现api文档
访问不了了。原因是没有设置WebFlux的 base-path
导致open api
的起始地址是/v3/api-docs
,nginx
代理命中不到导致404
有二种办法解决:
- 从
nginx
角度:配置nginx
对open api
的代理
location /v3/api-docs {
proxy_pass http://localhost:8080;
add_header Access-Control-Allow-Origin '*';
add_header Access-Control-Allow-Methods 'GET, POST, OPTIONS';
add_header Access-Control-Allow-Headers 'DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Conten t-Type,Authorization';
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Accept-Encoding '';
proxy_cache_valid any 1m;
if ($request_method = 'OPTIONS') {
return 204;
}
}
- 从
WebFlux
的角度:配置WebFlux的 base-path
spring:
webflux:
base-path: /api
# 去掉 forward-headers-strategy: framework 这个配置,不需要了
推荐第二种,简单明了。在项目中加了/api
请求前缀后,nginx
代理springboot
时去掉路径跟随即可,例如:
location /api {
proxy_pass http://v2-flow-server;// 这里没有 / ,表示nginx命中的/api不会传递到http://v2-flow-server/后面,省去了一层/api
add_header Access-Control-Allow-Origin '*';
add_header Access-Control-Allow-Methods 'GET, POST, OPTIONS';
add_header Access-Control-Allow-Headers 'DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Conten t-Type,Authorization';
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Accept-Encoding '';
proxy_cache_valid any 1m;
if ($request_method = 'OPTIONS') {
return 204;
}
}
好了,到这里全部完成。
评论区