Spring Cloud Gateway объединяет документы swagger

задняя часть Микросервисы Spring Swagger

​ О свинкеX:Новейшие каркасы микросервисов во всей сети, лучшие практики Spring Cloud Finchley и oAuth2

В микросервисной архитектуре каждый микросервис обычно использует Swagger для управления документами нашего интерфейса.Когда микросервисов становится все больше и больше, управление поиском в интерфейсе будет отнимать у нас много времени.В конце концов, лень – это добродетель программистов.

Поскольку swagger2 пока не поддерживает webflux, он прошел через множество ловушек.Спасибо @dreamlu @世yan за завершение этого эффекта.

Эффект агрегации документов

Получив доступ к host:port/swagger-ui.html шлюза, вы можете добиться:Портал предварительного просмотра эффекта документа агрегации свиней

Просмотрите документацию по swagger, выбрав сервисный модуль через Select the spec в правом верхнем углу.

Реализация ядра Pig's Zuul

Получите информацию о маршрутизации, настроенную zuul, в основном дляSwaggerResource

/**
* 参考jhipster
* GatewaySwaggerResourcesProvider
*/
@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 -> {
            //授权不维护到swagger
            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;
    }
}

Реализация Spring Cloud Gateway от PigX

ввести маршрут кSwaggerResource

@Component
@Primary
@AllArgsConstructor
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

@Slf4j
@Configuration
@AllArgsConstructor
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);

	}
}

Реализация бизнес-обработчика

	@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())));
	}

преобразование пути чванства

С помощью вышеуказанной конфигурации можно добиться ссылки и отображения документов, но использование чванстваtry it outПуть обнаружения функции — это путь после обрезания маршрута, например:

Путь в документации swagger: имя_хоста:порт:сопоставленный путь на один меньшепрефикс маршрута обслуживания, потому что обработчик отображения прошелStripPrefixGatewayFilterFactoryПри обработке этого фильтра исходный префикс маршрутизации отфильтровывается!

Вариант 1, вручную поддерживать префикс через конфигурацию хоста swagger.

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 в качестве префикса.

Благодаря приведенному выше анализу вы знаете, с чего начать, просто добавьте заголовок запроса к шлюзу.

@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);
		};
	}
}

Суммировать