Spring cloud Gateway 基於使用Netty
作為內嵌服務器,而Netty
基於WebFlux
實現,因此如果想要springdoc
的 Swagger UI 顯示在網關微服務中,需要用到它的WebFlux UI
庫。
現有三個微服務項目,分別是gateway-service
、shop-service
、user-service
,各依賴庫版本如下:
依賴 | 版本 |
---|---|
spring boot | 2.6.1 |
spring cloud | 2021.0.0 |
spring cloud alibaba | 2021.1 |
springdoc openapi | 1.5.13 |
由於只在gateway-service
網關微服務上查看 Swagger UI 頁面,因此另外兩個業務微服務中只需要添加springdoc openapi
的核心依賴庫即可:
...
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-webmvc-core</artifactId>
<version>${springdoc.version}</version>
</dependency>
...
而gateway-service
中除了spring cloud gateway
之外,還需要添加springdoc openapi webflux
依賴:
...
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<!-- spring cloud 2020之后的版本中不再自動引入Ribbon依賴,需要手動引入loadbalancer 否則會出現503錯誤 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-webflux-ui</artifactId>
<version>${springdoc.version}</version>
</dependency>
...
在user-service
和shop-service
中進行服務注冊、數據庫連接等基礎配置:
...
spring:
application:
name: user-service
cloud:
nacos:
discovery:
server-addr: localhost:8848
...
同時編寫 Swagger 自定義配置類:
@Configuration
public class SpringDocConfig {
@Bean
public OpenAPI customOpenApi() {
return new OpenAPI().info(new Info().title("User API")
.description("User API")
.version("v1.0.0")
.contact(new Contact()
.name("姓名")
.email("郵箱")));
}
}
此時已經可以通過訪問http://IP:微服務端口/v3/api-docs/
來獲取到openapi
的 JSON 格式數據了。
接下來需要在gateway-service
中獲取到其他服務的名稱,然后按服務名進行分組,可以參考 springdoc 微服務 demo 中的代碼:
@Configuration
public class SpringDocConfig {
@Bean
@Lazy(false)
public List<GroupedOpenApi> apis(SwaggerUiConfigParameters swaggerUiConfigParameters, RouteDefinitionLocator locator) {
List<GroupedOpenApi> groups = new ArrayList<>();
List<RouteDefinition> definitions = locator.getRouteDefinitions().collectList().block();
definitions.stream().filter(routeDefinition -> routeDefinition.getId().matches(".*-service"))
.forEach(routeDefinition -> {
String name = routeDefinition.getId().replaceAll("-service", "");
swaggerUiConfigParameters.addGroup(name);
GroupedOpenApi.builder().pathsToMatch("/" + name + "/**").group(name).build();
});
return groups;
}
@Bean
public OpenAPI customOpenApi() {
return new OpenAPI().info(new Info().title("springdoc gateway API")
.description("springdoc gateway API")
.version("v1.0.0")
.contact(new Contact()
.name("姓名")
.email("郵箱")));
}
}
這個配置可以將一個服務下的 API 按照服務名分組,通過http://IP:網關端口/v3/api-docs/組名
可以訪問對應 API 數據。為了使請求路徑更符合項目規范,將/v3/api-docs/組名
改為/組名/v3/api-docs
,需要對路由進行重寫:
...
spring:
application:
name: gateway-service
cloud:
nacos:
server-addr: localhost:8848
gateway:
discovery:
locator:
enabled: true
routes:
- id: user-route
uri: lb://user-service
predicates:
- Path=/user/**
filters:
- RewritePath=/user/(?<path>.*),/$\{path}
- id: shop-route
uri: lb://shop-service
predicates:
- Path=/shop/**
filters:
- RewritePath=/shop/(?<path>.*),/$\{path}
- id: openapi
uri: http://localhost:${server.port}
predicates:
- Path=/v3/api-docs/**
filters:
- RewritePath=/v3/api-docs/(?<path>.*),/$\{path}/v3/api-docs
springdoc:
swagger-ui:
use-root-path: true
urls:
- name: user
url: /v3/api-docs/user
- name: shop
url: /v3/api-docs/shop
...
至此,springdoc openapi
在 Spring Cloud Gateway 中的聚合已經完成了,通過網關微服務的swagger-ui.html
即可查看項目中其他微服務下的 API 接口。
另:如果在 Swagger UI 中使用 "Try it out" 功能出現跨域請求的錯誤,則需要額外進行一下配置
-
在 Controller 上添加
@CrossOrigin
注解,例:@RestController @CrossOrigin public class UserController { ... }
-
在網關微服務
application.yml
中添加配置:spring: cloud: gateway: globalcors: cors-configurations: '[/**]': allowedOrigins: "*" allowedMethods: - GET - POST - PUT - DELETE - OPTIONS