前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Spring Cloud Gateway 聚合swagger文档

Spring Cloud Gateway 聚合swagger文档

原创
作者头像
冷冷
修改2018-07-20 07:25:35
2.2K0
修改2018-07-20 07:25:35
举报
文章被收录于专栏:冷冷冷冷

关于pigX:全网最新的微服务脚手架,Spring Cloud Finchley、oAuth2的最佳实践

代码语言:txt
复制
在微服务架构下,通常每个微服务都会使用Swagger来管理我们的接口文档,当微服务越来越多,接口查找管理无形中要浪费我们不少时间,毕竟懒是程序员的美德。
代码语言:txt
复制
由于swagger2暂时不支持webflux 走了很多坑,完成这个效果感谢 @dreamlu @世言。

文档聚合效果

通过访问网关的 host:port/swagger-ui.html,即可实现: pig聚合文档效果预览传送门

通过右上角的Select a spec 选择服务模块来查看swagger文档

Pig的Zuul 核心实现

获取到zuul配置的路由信息,主要到**SwaggerResource**

代码语言:txt
复制


@Component

@Primary

public class RegistrySwaggerResourcesProvider implements SwaggerResourcesProvider {

    private final RouteLocator routeLocator;

    public RegistrySwaggerResourcesProvider(RouteLocator routeLocator) {

        this.routeLocator = routeLocator;

    }

    @Override

    public List<SwaggerResource> get() {

        List<SwaggerResource> resources = new ArrayList<>();

        List<Route> routes = routeLocator.getRoutes();

        routes.forEach(route -> {

            //授权不维护到swagge

            if (!StringUtils.contains(route.getId(), ServiceNameConstant.AUTH\_SERVICE)){

                resources.add(swaggerResource(route.getId(), route.getFullPath().replace("\*\*", "v2/api-docs")));

            }

        });

        return resources;

    }

    private SwaggerResource swaggerResource(String name, String location) {

        SwaggerResource swaggerResource = new SwaggerResource();

        swaggerResource.setName(name);

        swaggerResource.setLocation(location);

        swaggerResource.setSwaggerVersion("2.0");

        return swaggerResource;

    }

}

PigX的Spring Cloud Gateway 实现

注入路由到**SwaggerResource**
代码语言:txt
复制
@Component

@Primary

@AllArgsConstructo

public class SwaggerProvider implements SwaggerResourcesProvider {

    public static final String API\_URI = "/v2/api-docs";

    private final RouteLocator routeLocator;

    private final GatewayProperties gatewayProperties;


    @Override

    public List<SwaggerResource> get() {

        List<SwaggerResource> resources = new ArrayList<>();

        List<String> routes = new ArrayList<>();

        routeLocator.getRoutes().subscribe(route -> routes.add(route.getId()));

        gatewayProperties.getRoutes().stream().filter(routeDefinition -> routes.contains(routeDefinition.getId()))

            .forEach(routeDefinition -> routeDefinition.getPredicates().stream()

                .filter(predicateDefinition -> "Path".equalsIgnoreCase(predicateDefinition.getName()))

                .filter(predicateDefinition -> !"pigx-auth".equalsIgnoreCase(routeDefinition.getId()))

                .forEach(predicateDefinition -> resources.add(swaggerResource(routeDefinition.getId(),

                    predicateDefinition.getArgs().get(NameUtils.GENERATED\_NAME\_PREFIX + "0")

                        .replace("/\*\*", API\_URI)))));

        return resources;

    }

    private SwaggerResource swaggerResource(String name, String location) {

        SwaggerResource swaggerResource = new SwaggerResource();

        swaggerResource.setName(name);

        swaggerResource.setLocation(location);

        swaggerResource.setSwaggerVersion("2.0");

        return swaggerResource;

    }

}

提供swagger 对外接口配置



代码语言:txt
复制
@Slf4j

@Configuration

@AllArgsConstructo

public class RouterFunctionConfiguration {

    private final SwaggerResourceHandler swaggerResourceHandler;

    private final SwaggerSecurityHandler swaggerSecurityHandler;

    private final SwaggerUiHandler swaggerUiHandler;



    @Bean

    public RouterFunction routerFunction() {

        return RouterFunctions.route(

            .andRoute(RequestPredicates.GET("/swagger-resources")

                .and(RequestPredicates.accept(MediaType.ALL)), swaggerResourceHandler)

            .andRoute(RequestPredicates.GET("/swagger-resources/configuration/ui")

                .and(RequestPredicates.accept(MediaType.ALL)), swaggerUiHandler)

            .andRoute(RequestPredicates.GET("/swagger-resources/configuration/security")

                .and(RequestPredicates.accept(MediaType.ALL)), swaggerSecurityHandler);



    }

}

业务handler 的实现

代码语言:txt
复制
    @Override

    public Mono<ServerResponse> handle(ServerRequest request) {

        return ServerResponse.status(HttpStatus.OK)

            .contentType(MediaType.APPLICATION\_JSON\_UTF8)

            .body(BodyInserters.fromObject(swaggerResources.get()));

    }

    

    @Override

    public Mono<ServerResponse> handle(ServerRequest request) {

        return ServerResponse.status(HttpStatus.OK)

            .contentType(MediaType.APPLICATION\_JSON\_UTF8)

            .body(BodyInserters.fromObject(

                Optional.ofNullable(securityConfiguration)

                    .orElse(SecurityConfigurationBuilder.builder().build())));

    }

    

    @Override

    public Mono<ServerResponse> handle(ServerRequest request) {

        return ServerResponse.status(HttpStatus.OK)

            .contentType(MediaType.APPLICATION\_JSON\_UTF8)

            .body(BodyInserters.fromObject(

                Optional.ofNullable(uiConfiguration)

                    .orElse(UiConfigurationBuilder.builder().build())));

    }
swagger路径转换

通过以上配置,可以实现文档的参考和展示了,但是使用swagger 的 **try it out** 功能发现路径是路由切割后的路径比如:

swagger 文档中的路径为:

主机名:端口:映射路径 少了一个 **服务路由前缀**,是因为展示handler 经过了 **StripPrefixGatewayFilterFactory** 这个过滤器的处理,原有的 路由前缀被过滤掉了!

方案1,通过swagger 的host 配置手动维护一个前缀
代码语言:txt
复制
return new Docket(DocumentationType.SWAGGER\_2)

    .apiInfo(apiInfo())

    .host("主机名:端口:服务前缀")  //注意这里的主机名:端口是网关的地址和端口

    .select()

    .apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class))

    .paths(PathSelectors.any())

    .build()

    .globalOperationParameters(parameterList);
方案2,增加X-Forwarded-Prefix

swagger 在拼装URL 数据时候,会增加X-Forwarder-Prefix 请求头里面的信息为前缀

代码语言:txt
复制
@Component

public class SwaggerHeaderFilter extends AbstractGatewayFilterFactory {

    private static final String HEADER\_NAME = "X-Forwarded-Prefix";



    @Override

    public GatewayFilter apply(Object config) {

        return (exchange, chain) -> {

            ServerHttpRequest request = exchange.getRequest();

            String path = request.getURI().getPath();

            if (!StringUtils.endsWithIgnoreCase(path, SwaggerProvider.API\_URI)) {

                return chain.filter(exchange);

            }



            String basePath = path.substring(0, path.lastIndexOf(SwaggerProvider.API\_URI));





            ServerHttpRequest newRequest = request.mutate().header(HEADER\_NAME, basePath).build();

            ServerWebExchange newExchange = exchange.mutate().request(newRequest).build();

            return chain.filter(newExchange);

        };

    }

}

总结

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 文档聚合效果
  • Pig的Zuul 核心实现
  • PigX的Spring Cloud Gateway 实现
    • 注入路由到**SwaggerResource**
    • 提供swagger 对外接口配置
    • 业务handler 的实现
      • swagger路径转换
        • 方案1,通过swagger 的host 配置手动维护一个前缀
          • 方案2,增加X-Forwarded-Prefix
          • 总结
          领券
          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档