- test 服务中已配置分组
- 配置网关
- pom 添加依赖
<dependency> <groupId>io.springfox</groupId> <artifactId>springfox-swagger2</artifactId> <version>2.9.2</version> <scope>compile</scope> </dependency> <dependency> <groupId>io.springfox</groupId> <artifactId>springfox-swagger-ui</artifactId> <version>2.9.2</version> </dependency>
- 注入路由到 SwaggerResource
@Component @Primary public class SwaggerProvider implements SwaggerResourcesProvider { public static final String API_URI = "/v2/api-docs"; private RouteLocator routeLocator; private GatewayProperties gatewayProperties; @Override public List<SwaggerResource> get() { List<SwaggerResource> resources = new ArrayList<>(); List<String> routes = new ArrayList<>(); //取出gateway的route routeLocator.getRoutes().subscribe(route -> routes.add(route.getId())); //结合配置的route-路径(Path),和route过滤,只获取有效的route节点 gatewayProperties.getRoutes().stream().filter(routeDefinition -> routes.contains(routeDefinition.getId())) .forEach(routeDefinition -> routeDefinition.getPredicates().stream() .filter(predicateDefinition -> ("Path").equalsIgnoreCase(predicateDefinition.getName())) .forEach(predicateDefinition -> { // FIXME 能力有限想不出更好的实现方法来整合单个服务的分组问题 String name = routeDefinition.getId(); // name为服务名 if ("test".equals(name)) { String location = predicateDefinition.getArgs().get(NameUtils.GENERATED_NAME_PREFIX + "0") .replace("/**", API_URI); resources.add(swaggerResource(name + "/test1", location + "?group=test1")); resources.add(swaggerResource(name + "/test2", location + "?group=test2")); return; } resources.add(swaggerResource(name, 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; } @Autowired public SwaggerProvider(RouteLocator routeLocator, GatewayProperties gatewayProperties) { this.routeLocator = routeLocator; this.gatewayProperties = gatewayProperties; }
- 提供 Swagger 对外接口
@RestController @RequestMapping("/swagger-resources") public class SwaggerController { @Autowired(required = false) private SecurityConfiguration securityConfiguration; @Autowired(required = false) private UiConfiguration uiConfiguration; private final SwaggerResourcesProvider swaggerResources; @GetMapping("/configuration/security") public Mono<ResponseEntity<SecurityConfiguration>> securityConfiguration() { return Mono.just(new ResponseEntity<>( Optional.ofNullable(securityConfiguration).orElse(SecurityConfigurationBuilder.builder().build()), HttpStatus.OK)); } @GetMapping("/configuration/ui") public Mono<ResponseEntity<UiConfiguration>> uiConfiguration() { return Mono.just(new ResponseEntity<>( Optional.ofNullable(uiConfiguration).orElse(UiConfigurationBuilder.builder().build()), HttpStatus.OK)); } @GetMapping public Mono<ResponseEntity> swaggerResources() { return Mono.just((new ResponseEntity<>(swaggerResources.get(), HttpStatus.OK))); } @Autowired public SwaggerController(SwaggerResourcesProvider swaggerResources) { this.swaggerResources = swaggerResources; } }
- Swagger 路径转换
通过以上配置,可以实现文档的参考和展示了,但是使用 Swagger 的 try it out 功能发现路径是路由切割后的路径比如:
Swagger 文档中的路径为:
主机名:端口:映射路径 少了一个 服务路由前缀,是因为展示 handler 经过了 StripPrefixGatewayFilterFactory 这个过滤器的处理,原有的 路由前缀被过滤掉了!- 方案1:通过 Swagger 的 host 配置手动维护一个前缀
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
配置 appction.yml@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); }; } }
- id: test uri: lb://test predicates: - Path=/test/** filters: - SwaggerHeaderFilter - StripPrefix=1
- 方案1:通过 Swagger 的 host 配置手动维护一个前缀
- pom 添加依赖
- Nginx 配置
- Nginx 配置文件
# 配置使用用户名和密码登录 location /swagger-ui.html { auth_basic "test"; # 相对路径:htpasswd在机器上的位置:/usr/local/nginx/conf/htpasswd auth_basic_user_file htpasswd; # 绝对路径:htpasswd在机器上的位置:/tmp/htpasswd # auth_basic_user_file /tmp/htpasswd; proxy_pass http://**/swagger-ui.html; } location /swagger-resources { proxy_pass http://**/swagger-resources; } location /webjars { proxy_pass http://**/webjars; }
- 创建 htpasswd
# 格式:用户名:密码,注意密码是使用crypt加密过的 admin:PbSRr7orsxaso
- Nginx 配置文件
参考:Spring Cloud Gateway 聚合swagger文档
nginx配置指令auth_basic、auth_basic_user_file及相关知识