spring-cloud-gateway的简单使用

不同于zuul(基于servlet),spring-cloud-gateway 基于webflux

1.基于zookeeper作为服务注册与发现中心的spring-cloud-gateway的使用

使用zookeeper作为服务注册中心参考我的这篇文章spring-cloud使用zookeeper作为服务注册发现中心(下面会使用到该文章所建工程)

新建工程gateway

<groupId>com.wl.springcloud</groupId>
<artifactId>gateway</artifactId>
<version>1.0-SNAPSHOT</version>

pom.xml

<?xml version="1.0" encoding="UTF-8"?>

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>com.wl.springcloud</groupId>
  <artifactId>gateway</artifactId>
  <version>1.0-SNAPSHOT</version>

  <name>gateway</name>
  <!-- FIXME change it to the project's website -->
  <url>http://www.example.com</url>
  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.source>1.8</maven.compiler.source>
    <maven.compiler.target>1.8</maven.compiler.target>
    <spring-cloud-config-version>2.0.3.RELEASE</spring-cloud-config-version>
    <spring-cloud-eureka-server>2.0.3.RELEASE</spring-cloud-eureka-server>
    <spring-boot-version>2.0.8.RELEASE</spring-boot-version>
    <spring-cloud-zuul-version>2.0.3.RELEASE</spring-cloud-zuul-version>

    <spring-cloud-eureka-client-version>2.0.3.RELEASE</spring-cloud-eureka-client-version>
    <MainClass>com.wl.springcloud.gateway.GatewayApplication</MainClass>
  </properties>

  <dependencies>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-webflux</artifactId>
      <version>${spring-boot-version}</version>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-autoconfigure</artifactId>
      <version>${spring-boot-version}</version>
    </dependency>

    <!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-netflix-eureka-client -->
    <!--<dependency>-->
    <!--<groupId>org.springframework.cloud</groupId>-->
    <!--<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>-->
    <!--<version>${spring-cloud-eureka-client-version}</version>-->
    <!--</dependency>-->
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-actuator</artifactId>
      <version>${spring-boot-version}</version>
    </dependency>
    <dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-starter-config</artifactId>
      <version>${spring-cloud-config-version}</version>
    </dependency>

    <dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-starter-zookeeper-discovery</artifactId>
      <version>2.0.0.RELEASE</version>
      <exclusions>
        <exclusion>
          <groupId>org.apache.httpcomponents</groupId>
          <artifactId>httpclient</artifactId>
        </exclusion>
        <exclusion>
          <groupId>org.apache.zookeeper</groupId>
          <artifactId>zookeeper</artifactId>
        </exclusion>

      </exclusions>
    </dependency>

    <dependency>
      <groupId>org.apache.zookeeper</groupId>
      <artifactId>zookeeper</artifactId>
      <version>3.4.10</version>
    </dependency>

    <!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-gateway -->
    <dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-starter-gateway</artifactId>
      <version>2.0.3.RELEASE</version>
    </dependency>

    <dependency>
      <groupId>io.netty</groupId>
      <artifactId>netty-all</artifactId>
      <version>4.1.32.Final</version>
    </dependency>


    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-test</artifactId>
      <version>${spring-boot-version}</version>
      <scope>test</scope>
    </dependency>
  </dependencies>

  <!-- Package as an executable jar -->
  <build>
    <plugins>
      <plugin>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-maven-plugin</artifactId>
        <version>${spring-boot-version}</version>
        <configuration>
          <mainClass>${MainClass}</mainClass>
          <layout>JAR</layout>
        </configuration>
        <!-- repackage  生成两个 jar.original -->
        <executions>
          <execution>
            <goals>
              <goal>repackage</goal>
            </goals>
          </execution>
        </executions>
      </plugin>
      <!-- 指定maven 打包java 版本 -->
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>3.1</version>
        <configuration>
          <source>1.8</source>
          <target>1.8</target>
        </configuration>
      </plugin>
    </plugins>
    <!-- maven  编译打包resource 和 java 目录下所有文件  maven默认资源路径是resources -->
    <resources>
      <resource>
        <directory>src/main/resources</directory>
        <includes>
          <include>**/*.*</include>
          <include>*.*</include>
        </includes>
      </resource>
      <resource>
        <directory>src/main/java</directory>
        <includes>
          <include>**/*.*</include>
          <include>*.*</include>
        </includes>
      </resource>
    </resources>
  </build>

</project>

注意这里手动导入了netty-all依赖,如果没有这个依赖会报Caused by: java.lang.ClassNotFoundException: io.netty.resolver.DefaultAddressResolverGroup

application.yml(修改了zookeeper工程的服务id为zookeeper1,服务id与path路径相同时StripPrefix无效)

server:
  port: 8080
spring:
  cloud:
    zookeeper:
      connect-string: 192.168.245.130:2181
    gateway:
      discovery:
        locator:
          enabled: true
      routes:
      - id: zookeeper1
        uri: lb://zookeeper1
        predicates:
        - Path= /zookeeper/**
        filters:
        - StripPrefix=0
        #配置多个路由
#      - id: clientId
#        uri: lb://clientId
#        predicates:
#        - Path= /zookeeper/*
#        filters:
#        - StripPrefix=0

1.spring.cloud.gateway.discovery.locator.enable=true表示启用服务注册发现组件(可以通过服务id进行转发),默认为false

2.id表示注册到zookeeper上的服务实例id即spring-application-name

3.uri 与zuul中的url配置基本相同,可以是http路径也可以是服务id。与zuul直接使用服务id不同,spring-cloud-gateway需要写成lb://服务id

4.Path 与zuul中path相同 。这里表示以/zookeeper 开始的路径将转发到zookeeper1服务上

扫描二维码关注公众号,回复: 12811022 查看本文章

5.StripPrefix表示去掉前缀的数量。例如StripPrefix=1 则请求 /name/bar/foo 转发到目标服务的路径为/bar/foo。以此类推值为2则转发到目标服务的路径为/foo。注意StripPrefix=0等价于zuul中stripPrefix=false,StripPrefix=1等价于zuul中stripPrefix=true

6.predicates(路由方式)、filters(过滤器)配置。下面介绍过滤器时会进行详细说明。这两个配置主要针对org.springframework.cloud.gateway.filter.factory、org.springframework.cloud.gateway.handler.predicate中的类,Path、StripPrefix分别是PathRoutePredicateFactory、StripPrefixGatewayFilterFactory的前缀,当然还有更多的pridicate 和 filter

启动类

package com.wl.springcloud.gateway;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.gson.GsonAutoConfiguration;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration;
import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration;

/**
 * Created by Administrator on 2019/4/22.
 */
@SpringBootApplication(exclude = {
        DataSourceAutoConfiguration.class,
        DataSourceTransactionManagerAutoConfiguration.class,
        HibernateJpaAutoConfiguration.class,             //不使用数据库
        GsonAutoConfiguration.class                      //spring-boot2.0.0以上版本需要引入高版本的gson依赖,如果不引用gson依赖需要加此属性
},scanBasePackages = "com.wl")
public class GatewayApplication {
    private static final Logger logger = LoggerFactory.getLogger(GatewayApplication.class);

    public static void main(String[] args) {
        SpringApplication.run(GatewayApplication.class);
    }
}

启动gateway和zookeeper(注意修改spring.application.name=zookeeper1)工程

浏览器输入http://localhost:8080/zookeeper/zookeeper

 2.spring-cloud-gateway 过滤器

2.1 GatewayFilter

      GatewayFilter是路由绑定的过滤器,只会在绑定的路由中执行

      自定义GatewayFilter有两种方式:1.通过实现GatewayFilter   2.通过自定义GatewayFilterFactory然后通过RouteDefinitionRouteLocator类中的loadGatewayFilters方法加载到过滤器链中

方式一

过滤器

package com.wl.springcloud.gateway.filter;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.core.Ordered;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import reactor.ipc.netty.ByteBufFlux;

import java.util.HashMap;
import java.util.Map;

/**
 * Created by Administrator on 2019/4/22.
 */
public class AuthGateWayFilter implements GatewayFilter,Ordered {

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        String token = request.getQueryParams().getFirst("token");
        if(token != null && !token.equals("")){
            return chain.filter(exchange);
        }
        
        ServerHttpResponse response = exchange.getResponse();
        //设置http响应状态码
        response.setStatusCode(HttpStatus.BAD_REQUEST);
        //设置响应头信息Content-Type类型
        response.getHeaders().add("Content-Type","application/json");
        //设置返回json数据
        return response.writeAndFlushWith(Flux.just(ByteBufFlux.just(response.bufferFactory().wrap(getWrapData()))));
        //直接返回(没有返回数据)
//        return response.setComplete().then();
        //设置返回的数据(非json格式)
//        return response.writeWith(Flux.just(response.bufferFactory().wrap("".getBytes())));

    }

    @Override
    public int getOrder() {
        return Ordered.HIGHEST_PRECEDENCE;
    }

    private byte[] getWrapData() {
        Map<String,String> map = new HashMap<>();
        map.put("code","1");
        map.put("msg","token is empty or illegal");
        try {
            return new ObjectMapper().writeValueAsString(map).getBytes();
        } catch (JsonProcessingException e) {
            //
        }
        return "".getBytes();
    }
}

这是一个自定义的校验token的过滤器,如果token为空则返回{"msg":"token is empty or illegal","code":"1"}的json数据

1.如果不需要返回数据则直接response.setComplete()

2.如果返回的不是json格式的数据则response.writeWith(Flux.just(response.bufferFactory().wrap(data)))或response.writeWith(Mono.just(response.bufferFactory().wrap(data)))

3.如果返回的是application/json格式的数据则response.writeAndFlushWith(Flux.just(ByteBufFlux.just(response.bufferFactory().wrap(getWrapData()))))或

response.writeAndFlushWith(Mono.just(ByteBufMono.just(response.bufferFactory().wrap(getWrapData()))))

4.Flux 与Mono 的区别参考https://www.jianshu.com/p/611f3667c4d2

5.注意writeWith与writeAndFlushWith的参数的泛型区别,所以在writeAndFlushWith需要使用Flux包装两次

将过滤器绑定在某一个路由上

package com.wl.springcloud.gateway.config;

import com.wl.springcloud.gateway.filter.AuthGateWayFilter;
import org.springframework.cloud.gateway.route.Route;
import org.springframework.cloud.gateway.route.RouteLocator;
import org.springframework.cloud.gateway.route.builder.GatewayFilterSpec;
import org.springframework.cloud.gateway.route.builder.PredicateSpec;
import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder;
import org.springframework.cloud.gateway.route.builder.UriSpec;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.function.Function;

/**
 * Created by Administrator on 2019/4/23.
 */
@Configuration
public class GatewayFilterConfig {

    @Bean
    public RouteLocator customerRouteLocator(RouteLocatorBuilder builder) {
        return builder.routes().route(new Function<PredicateSpec, Route.AsyncBuilder>() {
            @Override
            public Route.AsyncBuilder apply(PredicateSpec predicateSpec) {
                return predicateSpec.path("/zookeeper/**").filters(new Function<GatewayFilterSpec, UriSpec>() {
                    @Override
                    public UriSpec apply(GatewayFilterSpec gatewayFilterSpec) {
                        return gatewayFilterSpec.filter(new AuthGateWayFilter()).stripPrefix(0);
                    }
                }).uri("lb://zookeeper1").order(0).id("zookeeper1");

            }
        }).build();
    }
}

这里将过滤器绑定在了/zookeeper/**这个路由上

浏览器输入http://localhost:8080/zookeeper/zookeeper

浏览器输入http://localhost:8080/zookeeper/zookeeper?token=123

方式二 使用GatewayFilterFactory 参考StripPrefixGatewayFilterFactory

package com.wl.springcloud.gateway.filter.factory;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import reactor.ipc.netty.ByteBufFlux;

import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Created by Administrator on 2019/4/23.
 */
@Component
public class AuthGatewayFilterFactory extends AbstractGatewayFilterFactory<AuthGatewayFilterFactory.Config> {

    private final String KEY = "token";

    public AuthGatewayFilterFactory() {
        super(Config.class);
    }

    @Override
    public List<String> shortcutFieldOrder() {
        return Arrays.asList("enabled");
    }


    @Override
    public GatewayFilter apply(Config config) {
        return new GatewayFilter() {
            @Override
            public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
                if(!config.enabled){
                    return chain.filter(exchange);
                }
                ServerHttpRequest request = exchange.getRequest();
                String token = request.getQueryParams().getFirst(KEY);
                if(token != null && !token.equals("")){
                    return chain.filter(exchange);
                }

                ServerHttpResponse response = exchange.getResponse();
                //设置http响应状态码
                response.setStatusCode(HttpStatus.BAD_REQUEST);
                //设置响应头信息Content-Type类型
                response.getHeaders().add("Content-Type","application/json");
                //设置返回json数据
                return response.writeAndFlushWith(Flux.just(ByteBufFlux.just(response.bufferFactory().wrap(getWrapData()))));
                //直接返回(没有返回数据)
//        return response.setComplete().then();
                //设置返回的数据(非json格式)
//        return response.writeWith(Flux.just(response.bufferFactory().wrap("".getBytes())));
            }
            private byte[] getWrapData() {
                Map<String,String> map = new HashMap<>();
                map.put("code","1");
                map.put("msg","token is empty or illegal");
                try {
                    return new ObjectMapper().writeValueAsString(map).getBytes();
                } catch (JsonProcessingException e) {
                    //
                }
                return "".getBytes();
            }
        };

    }

    public static class Config {
        private boolean enabled;

        public boolean isEnabled() {
            return enabled;
        }

        public void setEnabled(boolean enabled) {
            this.enabled = enabled;
        }
    }
}

修改配置

server:
  port: 8080
spring:
  cloud:
    zookeeper:
      connect-string: 192.168.245.130:2181
    gateway:
      discovery:
        locator:
          enabled: true
      routes:
      - id: zookeeper1
        uri: lb://zookeeper1
        predicates:
        - Path= /zookeeper/**
        filters:
        - StripPrefix=0
        - Auth=true
        #配置多个路由
#      - id: zookeeper1
#        uri: lb://zookeeper1
#        predicates:
#        - Path= /zookeeper/**
#        filters:
#        - StripPrefix=0

配置添加了- Auth=true

注意filters配置里面的StripPrefix和Auth是StripPrefixGatewayFilterFactory和AuthGatewayFilterFactory的前缀,分别代表了两个GatewayFilterFactory的名称,后面的值0和true会通过

@Override
public List<String> shortcutFieldOrder() {
    return Arrays.asList("enabled");
}
public static final String PARTS_KEY = "parts";
@Override
public List<String> shortcutFieldOrder() {
   return Arrays.asList(PARTS_KEY);
}

传递到其内部类Config的属性中(属性名称与Arrays.asList() 中的字符串相同)即StripPrefixGatewayFilterFactory.Config中的属性名称parts与Arrays.asList(PARTS_KEY)中的PARTS_KEY相同;AuthGatewayFilterFactory.Config中的属性名称enabled与Arrays.asList("enabled")相同

注意不要忘记AuthGatewayFilterFactory类上的@Component注解

配置- Auth=true之后会通过RouteDefinitionRouteLocator类中的loadGatewayFilters方法加载到过滤器链中。

更多GatewayFilterFactory在org.springframework.cloud.gateway.filter.factory包中

相同的 predicates的配置对应的有RoutePredicateFactory接口,Path是PathRoutePredicateFactory的前缀,代表了PathRoutePredicateFactory的名称,后面的值/zookeeper/**会通过

@Override
public List<String> shortcutFieldOrder() {
   return Arrays.asList(PATTERN_KEY, MATCH_OPTIONAL_TRAILING_SEPARATOR_KEY);
}

传递到其内部类Config的pattern属性中。可以看到其内部类中有三个属性名称分别对应的与Arrays.asList(PATTERN_KEY, MATCH_OPTIONAL_TRAILING_SEPARATOR_KEY)中的参数名称相同

更多的RoutePredicateFactory在org.springframework.cloud.gateway.handler.predicate中

其它的RoutePredicateFactory和GatewayFilterFactory以此类推!

 将之前的过滤器注释掉并重启应用

浏览器输入http://localhost:8080/zookeeper/zookeeper

 2.2GlobalFilter

顾名思义为全局的过滤器

自定义GlobalFilter非常简单只需实现GlobalFilter即可

package com.wl.springcloud.gateway.filter;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import reactor.ipc.netty.ByteBufFlux;

import java.util.HashMap;
import java.util.Map;

/**
 * Created by Administrator on 2019/4/24.
 */
@Component
public class GlobalAuthFilter implements GlobalFilter,Ordered {
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        String token = request.getQueryParams().getFirst("token");
        if(token != null && !token.equals("")){
            return chain.filter(exchange);
        }

        ServerHttpResponse response = exchange.getResponse();
        //设置http响应状态码
        response.setStatusCode(HttpStatus.BAD_REQUEST);
        //设置响应头信息Content-Type类型
        response.getHeaders().add("Content-Type","application/json");
        //设置返回json数据
        return response.writeAndFlushWith(Flux.just(ByteBufFlux.just(response.bufferFactory().wrap(getWrapData()))));
        //直接返回(没有返回数据)
//        return response.setComplete().then();
        //设置返回的数据(非json格式)
//        return response.writeWith(Flux.just(response.bufferFactory().wrap("".getBytes())));
    }

    private byte[] getWrapData() {
        Map<String,String> map = new HashMap<>();
        map.put("code","1");
        map.put("msg","token is empty or illegal");
        map.put("filter","global");
        try {
            return new ObjectMapper().writeValueAsString(map).getBytes();
        } catch (JsonProcessingException e) {
            //
        }
        return "".getBytes();
    }

    @Override
    public int getOrder() {
        return 0;
    }
}

配置增加一个/abc/**的路由

server:
  port: 8080
spring:
  cloud:
    zookeeper:
      connect-string: 192.168.245.130:2181
    gateway:
      discovery:
        locator:
          enabled: true
      routes:
      - id: zookeeper1
        uri: lb://zookeeper1
        predicates:
        - Path= /zookeeper/**
        filters:
        - StripPrefix=0
        - Auth=true
        #配置多个路由
      - id: zookeeper1
        uri: lb://zookeeper1
        predicates:
        - Path= /abc/**
        filters:
        - StripPrefix=1

浏览器输入

http://localhost:8080/abc/zookeeper/zookeeper

 加上token

3.HystrixGatewayFilterFactory配置服务熔断、降级(由名字可见是绑定路由的过滤器)

加入依赖

    <!-- 熔断、降级 -->
    <dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
      <version>2.0.3.RELEASE</version>
    </dependency>

修改配置

server:
  port: 8080
spring:
  cloud:
    zookeeper:
      connect-string: 192.168.245.130:2181
    gateway:
      discovery:
        locator:
          enabled: true
      routes:
      - id: zookeeper1
        uri: lb://zookeeper1
        predicates:
        - Path= /zookeeper/**
        filters:
        - StripPrefix=0
        - Auth=true
        - name: Hystrix
          args:
            name: fallbackcmd
            fallbackUri: forward:/fallbackUri
        #配置多个路由
      - id: zookeeper1
        uri: lb://zookeeper1
        predicates:
        - Path= /abc/**
        filters:
        - StripPrefix=1
        - name: Hystrix
          args:
            name: fallbackcmd
            fallbackUri: forward:/fallbackUri

fallbackUri是服务降级后访问的路径

package com.wl.springcloud.gateway.fallback;

import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.server.ServerWebExchange;

/**
 * Created by Administrator on 2019/5/24.
 */
@RestController
public class GatewayFallback  {

    @RequestMapping(value = "/fallbackUri",produces = {MediaType.APPLICATION_JSON_VALUE})
    public Object fallbackUri(ServerWebExchange exchange){

        return "服务降级";
    }


}

hystrix超时配置

hystrix:
  command:
    fallbackcmd:
      execution:
        isolation:
          strategy: SEMAPHORE
          thread:
            timeoutInMilliseconds: 2000
            shareSecurityContext: true

command后fallbackcmd与上面Hystrix args中的name绑定

Spring-cloud-gateway更多GatewayFilterFactory 参考https://www.cnblogs.com/liukaifeng/p/10055863.html

Spring Cloud GateWay动态路由配置参考https://blog.csdn.net/lazasha/article/details/84942823

使用eureka作为服务注册发现中心参考我的另一篇文章spring-cloud-starter-netflix-zuul(原spring-cloud-starter-zuul)的使用

猜你喜欢

转载自blog.csdn.net/name_is_wl/article/details/89460817