Spring Cloud Gateway、Swagger、Nginx整合

  1. test 服務中已配置分組
    在這裏插入圖片描述
  2. 配置網關
    1. 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>
      
    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及相關知識

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章