当前位置: 代码迷 >> 综合 >> Gateway/Zuul + OpenApi 集中管理 API 资源
  详细解决方案

Gateway/Zuul + OpenApi 集中管理 API 资源

热度:109   发布时间:2023-09-27 15:54:52.0

Gateway + OpenApi

为了启用 OpenApi,提供 API 的服务中需要添加以下依赖:

<dependency><groupId>org.springdoc</groupId><artifactId>springdoc-openapi-webmvc-core</artifactId><version>1.4.1</version>
</dependency>

我们的 gateway,Spring Cloud Gateway 使用 Netty 作为内嵌服务器,Netty 基于 Spring WebFlux。同时,为了显示 UI 界面,也要提供相应的库:

<dependency><groupId>org.springdoc</groupId><artifactId>springdoc-openapi-webflux-core</artifactId><version>1.4.1</version></dependency><dependency><groupId>org.springdoc</groupId><artifactId>springdoc-openapi-webflux-ui</artifactId><version>1.4.1</version></dependency>

每个微服务都会暴露 /v3/api-docs 接口,用来获取 API 信息。可以通过 springdoc.api-docs.path 配置来修改这个路由,建议不修改。不同于 Swagger,OpenAPI 并不提供类似 SwaggerResource 可以用来收集这些 API 信息的类

幸运的是,我们可以使用 SwaggerUiConfigProperties 来实现我们的目的(这里 IDEA 会说找不到这个 bean,但实际并不影响)

@Component
public class OpenApiConfig {
    public OpenApiConfig(RouteLocator locator, SwaggerUiConfigProperties swaggerUiConfig) {
    List<Route> routes = routeLocator.getRoutes();// 去重Collection<Route> distinctRoutes = routes.stream().collect(Collectors.toMap(Route::getLocation, p -> p, (p, q) -> p)).values();// 将服务名添加到下拉框distinctRoutes.stream().filter(route -> route.getLocation().matches(".+-service")).forEach(route -> {
    String serviceName = route.getLocation();swaggerUiConfig.addGroup(serviceName);}
}

SwaggeUiConfig.addGroup(serviceName ) 会在 UI 界面上生成一个下拉框,并加入一个名为 serviceName 的选项。点击这个选项将会访问 /v3/api-docs/serviceName,而我们期望的是 /serviceName/v3/api-docs。所以,需要对路由进行重写

在此之前,需要配置我们的路由

spring:application:name: gatewaycloud:gateway:discovery:locator:enabled: trueroutes:- id: user-serviceuri: lb://user-servicepredicates:- Path=/user/**filters:- RewritePath=/user/(?<path>.*), /$\{
    path}- id: task-serviceuri: lb://task-servicepredicates:- Path=/task/**filters:- RewritePath=/task/(?<path>.*), /$\{
    path}

uri: lb//user-service 将自动实现所有 user-service 实例间的负载均衡。 RewritePath=/service/(?<path>.*), /$\{path} 将在访问请求时去掉 /service 前缀

然后,将 /v3/api-docs/serviceName 的路由重写为 /serviceName/v3/api-docs

- id: openapiuri: http://localhost:${
    server.port}predicates:- Path=/v3/api-docs/**filters:- RewritePath=/v3/api-docs/(?<path>.*), /$\{
    path}/v3/api-docs

最后效果呈现如下:
Gateway/Zuul + OpenApi 集中管理 API 资源

Zuul + OpenApi

Zuul 内嵌的是 Tomcat,不需要 WebFlux 加持,所以使用以下依赖

<dependency><groupId>org.springdoc</groupId><artifactId>springdoc-openapi-ui</artifactId><version>1.4.1</version>
</dependency>

OpenApiConfig 和前半节中的相同

Zuul 中 路由配置:

spring:application:name: gatewayzuul:ignoredPatterns:- /v3/api-docs- /v3/api-docs/swagger-configroutes:user:service-id: user-servicepath: /user/**task:service-id: task-servicepath: /task/**apis:service-id: gatewaypath: /v3/api-docs/**

/v3/api-docs/swagger-config 并不需要路由,所以加到 ignoredPatterns

如我们看到的,Zuul 不提供 Gateway 中的 RewritePath。我们可以使用过滤器来完成重写路由的工作:

@Component
public class UrlPathFilter extends ZuulFilter {
    @Overridepublic String filterType() {
    return "route";}@Overridepublic int filterOrder() {
    return 0;}@Overridepublic boolean shouldFilter() {
    String requestURI = RequestContext.getCurrentContext().getRequest().getRequestURI();return requestURI.matches("/v3/api-docs/.+");}@Overridepublic Object run() {
    String requestURI = RequestContext.getCurrentContext().getRequest().getRequestURI();// 提取出路由最后一节,即服务名String servicePattern = "/v3/api-docs/(?<group>.+)";Pattern compile = Pattern.compile(servicePattern);Matcher matcher = compile.matcher(requestURI);String group = "";while (matcher.find()) {
    group = matcher.group("group");}// 重写路由String path = "/" + group + "/v3/api-docs";RequestContext context = RequestContext.getCurrentContext();context.put(FilterConstants.REQUEST_URI_KEY, path);System.out.println(path);return null;}
}

最后的效果和上面相同

  相关解决方案