Spring Cloud Gateway, Swagger, Nginx Integration

Keywords: Nginx Spring

  1. Groups already configured in the test service
  2. configure gateway
    1. Adding dependencies to 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. Injection Routing to 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<>();
              //Remove route from gateway
              routeLocator.getRoutes().subscribe(route -> routes.add(route.getId()));
              //Combining route-path (Path) configuration with route filtering, only valid route nodes are obtained.
              gatewayProperties.getRoutes().stream().filter(routeDefinition -> routes.contains(routeDefinition.getId()))
                      .forEach(routeDefinition -> routeDefinition.getPredicates().stream()
                              .filter(predicateDefinition -> ("Path").equalsIgnoreCase(predicateDefinition.getName()))
                              .forEach(predicateDefinition -> {
                                  // FIXME has limited capabilities and can't think of a better way to integrate the grouping of individual services
                                  String name = routeDefinition.getId();
                                  // Name is the service 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. Provide Swagger External Interface
      @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 Path Conversion

      With the above configuration, the document can be referenced and displayed, but using Swagger's try it out function, it can be found that the path is the path after route cutting, such as:
      The path in the Swagger document is:
      Host Name: Port: The mapping path is missing a service routing prefix because the display handler has been processed by the Strip Prefix Gateway FilterFactory filter, and the original routing prefix has been filtered out!

      1. Solution 1: Manually maintain a prefix through Swagger's host configuration
        return new Docket(DocumentationType.SWAGGER_2)
            .apiInfo(apiInfo())
            .host("Host name: port: service prefix")  //Note the hostname here: the port is the address and port of the gateway
            .select()
            .apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class))
            .paths(PathSelectors.any())
            .build()
            .globalOperationParameters(parameterList);
        
      2. Solution 2: Add 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);
                };
            }
        }
        
        Configure appction.yml
        - id: test
          uri: lb://test
          predicates:
          - Path=/test/**
          filters:
          - SwaggerHeaderFilter
          - StripPrefix=1
        
  3. Nginx configuration
    1. Nginx configuration file
      	# Configure login with username and password
      	location /swagger-ui.html {
              auth_basic "test";
              # Relative path: the location of htpasswd on the machine: / usr/local/nginx/conf/htpasswd
              auth_basic_user_file htpasswd;
              # Absolute path: the location of htpasswd on the machine: / 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. Create htpasswd
      # Format: Username: Password, note that the password is encrypted using crypt
      admin:PbSRr7orsxaso
      

Reference resources: Spring Cloud Gateway aggregates swagger documents
nginx configuration instructions auth_basic, auth_basic_user_file and related knowledge

Posted by ca87 on Mon, 14 Oct 2019 12:18:57 -0700