Spring Cloud Gateway、Swagger、Nginx整合

  1. test 服务中已配置分组
    Spring Cloud Gateway、Swagger、Nginx整合_第1张图片
  2. 配置网关
    1. pom 添加依赖
      <dependency>
          <groupId>io.springfoxgroupId>
          <artifactId>springfox-swagger2artifactId>
          <version>2.9.2version>
          <scope>compilescope>
      dependency>
      <dependency>
          <groupId>io.springfoxgroupId>
          <artifactId>springfox-swagger-uiartifactId>
          <version>2.9.2version>
      dependency>
      
    2. 注入路由到 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;
          }
      
    3. 提供 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;
          }
      
      }
      
    4. Swagger 路径转换

      通过以上配置,可以实现文档的参考和展示了,但是使用 Swagger 的 try it out 功能发现路径是路由切割后的路径比如:
      Swagger 文档中的路径为:
      主机名:端口:映射路径 少了一个 服务路由前缀,是因为展示 handler 经过了 StripPrefixGatewayFilterFactory 这个过滤器的处理,原有的 路由前缀被过滤掉了!

      1. 方案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. 方案2:增加 X-Forwarded-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);
                };
            }
        }
        
        配置 appction.yml
        - id: test
          uri: lb://test
          predicates:
          - Path=/test/**
          filters:
          - SwaggerHeaderFilter
          - StripPrefix=1
        
  3. Nginx 配置
    1. 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://zxjl/swagger-ui.html;
          }
      
          location /swagger-resources {
          	proxy_pass http://zxjl/swagger-resources;
          }
      
          location /webjars {
          	proxy_pass http://zxjl/webjars;
          }
      
    2. 创建 htpasswd
      # 格式:用户名:密码,注意密码是使用crypt加密过的
      admin:PbSRr7orsxaso
      

参考:Spring Cloud Gateway 聚合swagger文档
nginx配置指令auth_basic、auth_basic_user_file及相关知识

你可能感兴趣的:(Java,SpringCloud,Nginx)