一 Gateway介绍

    Spring Cloud Gateway 是基于 Spring WebFlux 和 Project Reactor 构建的新一代 API 网关,是 Spring Cloud 官方推荐替代 Zuul 的轻量级、高性能网关。API网关就是指系统的统一入口,提供内部服务的路由中转,为客户端提供统一服务,一些与业务本身功能无关的公共逻辑可以在这里实现,诸如认证、鉴权、监控、路由转发等。

网关作用定位:
网关作用定位
核心功能:

  • 动态路由:支持基于 Predicate(断言)+ Filter 链式匹配,支持路径、主机、方法、Header、参数、Host、Cookie 等多种匹配条件
  • 全局/路由级 Filter:提供请求前置、后置处理,支持鉴权、限流、熔断、日志、跨域、请求头添加/移除等
  • 内置强大 Route Predicate Factories 和 Route Filter Factories(如 Retry、CircuitBreaker、RequestRateLimiter)
  • 与 Spring Cloud LoadBalancer、DiscoveryClient 无缝集成,支持服务发现自动路由(Nacos、Eureka、Consul 等)
  • 支持 WebSocket 路由、TLS/SSL 终结
  • 深度集成 Resilience4j(限流、熔断、超时)、Sentinel、Spring Cloud CircuitBreaker

典型应用场景:

  • 微服务统一入口与流量聚合
  • 动态路由与灰度发布、金丝雀发布
  • 统一认证鉴权(GatewayFilter + OAuth2/JWT)
  • 跨域处理、请求响应改造
  • 结合 Hystrix/Resilience4j 实现服务熔断降级
  • 前后端分离项目、移动端网关、BFF(Backend For Frontend)模式

二 调用组件SpringCloud Gateway示例

1. 引入Gateway依赖

    在网关模块引入依赖

      <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-gateway</artifactId>
        </dependency>
        <!--   Nacos服务发现 -->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
        <dependency>
           <groupId>org.springframework.cloud</groupId>
           <artifactId>spring-cloud-starter-loadbalancer</artifactId>
       </dependency>

2. 在启动类开启@EnableDiscoveryClient注解

@EnableDiscoveryClient
@SpringBootApplication
public class GatewayApplication {

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

}

3. 编写Gateway配置项

spring:
  cloud:
    gateway:
      routes:
        - id : order-route
          uri: lb://order-service
          predicates:
            - Path=/api/order/**
          order: 1

        - id : user-route
          uri: lb://user-service
          predicates:
            - Path=/api/user/**
          order: 2

4. Gateway调用流程

调用流程

三 Gateway路由断言Predicate

    SpringCloud Gateway 的断言(Predicates)是路由匹配的核心规则,用于根据请求属性动态决策路由路径。Gateway 内置很多路由断言,部分展示如下所示。
断言类别

1. Query断言

    例如Query 断言,

spring:
  cloud:
    gateway:
      routes:
        - id: bingying-route
          uri:  https://www.bing.com
          predicates:
            - Path=/search
            - name: Query
              args:
                param: q
                regexp: abc

工作原理:

  • 提取URL中的查询参数部分(?后面的内容)
  • 检查是否存在名为param的参数
  • 将参数值与regexp进行正则匹配
  • 都满足返回true
    请求 你的IP/search?q=abc, 跳转必应搜索页面:
    必应

2. 自定义断言

    内置的断言可能无法满足业务需求,你有需要满足一定条件才能访问功能的要求。
实现自定义断言,需继承AbstractRoutePredicateFactory,命名规则:XxxRoutePredicateFactory。

// 自定义Role 的断言工厂
@Component
public class RoleRoutePredicateFactory extends AbstractRoutePredicateFactory<RoleRoutePredicateFactory.Config> {

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

    @Override
    public Predicate<ServerWebExchange> apply(Config config) {
        return new GatewayPredicate() {
            @Override
            public boolean test(ServerWebExchange serverWebExchange) {
                ServerHttpRequest request = serverWebExchange.getRequest();
                String first = request.getQueryParams().getFirst(config.param);
                return StringUtils.hasText(first)&&first.equals(config.value);
            }
        };
    }

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


    @Validated
    public static class Config {

        @NotEmpty
        private String param;
        @NotEmpty
        private String value;

        public String getParam() {
            return param;
        }

        public void setParam(String param) {
            this.param = param;
        }

        public void setValue(String value) {
            this.value = value;
        }

        public String getValue() {
            return value;
        }
    }

}

    添加配置

spring:
  cloud:
    gateway:
      routes:
        - id: bingying-route
          uri:  https://www.bing.com
          predicates:
            - Path=/search
            - name: Query
              args:
                param: q
                regexp: abc
            - Role=user,admin

3. 过滤器

    在 Gateway 的过滤器中又可以分为 局部过滤器和全局过滤器。局部是用于某一个路由上的,全局是用于所有路由上的。Gateway 内置很多过滤器,部分展示如下所示。
过滤器
在配置添加内置过滤器。

spring:
  cloud:
    gateway:
      routes:
        - id : order-route
          uri: lb://order-service
          predicates:
            - Path=/api/order/**
          order: 1

        - id : user-route
          uri: lb://user-service
          predicates:
            - Path=/api/user/**
          order: 2

        - id: bingying-route
          uri: https://www.bing.com
          predicates:
            - Path=/search
            - name: Query
              args:
                param: q
                regexp: abc
      # 默认filter
      default-filters:
        - AddResponseHeader=X-Response-Red,111

    Gateway支持自定义全局过滤器。
实现自定义全局过滤器,需继承GlobalFilter, Ordered。

// 全局过滤器
@Component
@Slf4j
public class RtGlobalFilter implements GlobalFilter, Ordered {
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request= exchange.getRequest();
        ServerHttpResponse response=exchange.getResponse();
        String uri=request.getURI().toString();
        long start=System.currentTimeMillis();

        log.info("请求【{}】开始时间:{}",uri,start);

        // 后置逻辑
        Mono<Void> filter = chain.filter(exchange).doFinally(
                (result)->{
                    long end = System.currentTimeMillis();
                    log.info("请求【{}】结束时间:{},耗时:{}ms",uri,end,end-start);
                }
        );
        return filter;
    }

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

    Gateway支持自定义过滤器工厂。
实现自定义局部过滤器,可继承AbstractNameValueGatewayFilterFactory。

@Component
public class OnceTokenGatewayFilterFactory extends AbstractNameValueGatewayFilterFactory {
    @Override
    public GatewayFilter apply(NameValueConfig config) {
        return new GatewayFilter() {
            @Override
            public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
                // 每次响应之前,添加一次性令牌
                return chain.filter(exchange).then(Mono.fromRunnable(()->{
                    ServerHttpResponse response = exchange.getResponse();
                    HttpHeaders headers =  response.getHeaders();
                    String value = config.getValue();
                    //UUID 方式
                    if("uuid".equalsIgnoreCase(value)){
                        value= UUID.randomUUID().toString();
                    }

                    headers.add(config.getName(),value);
                }));
            }
        };
    }
}

    在所需服务添加配置OnceToken过滤器。

spring:
  cloud:
    gateway:
      routes:
        - id : order-route
          uri: lb://order-service
          predicates:
            - Path=/api/order/**
          # 配置自定义过滤器工厂
          filters:
            - OnceToken=X-Response-Token,uuid
          order: 1

        - id : user-route
          uri: lb://user-service
          predicates:
            - Path=/api/user/**
          order: 2

        - id: bingying-route
          uri: https://www.bing.com
          predicates:
            - Path=/search
            - name: Query
              args:
                param: q
                regexp: abc
      # 默认filter
      default-filters:
        - AddResponseHeader=X-Response-Red,111

4. 网关跨域设置

    当一个浏览器请求url的协议、域名、端口三者之间的任意一个与当前页面url不同即为跨域。浏览器在访问网关的时候存在跨域,而网关访问服务是不存在跨域的,因为跨域问题是浏览器与服务之间的问题。
    在yml配置文件添加配置。

spring:
  cloud:
    gateway:
      globalcors:
        cors-configurations:
          '[/**]':
            allowed-origin-patterns: '*'
            allowed-headers: '*'
            allowed-methods: '*'
      routes:
        - id : order-route
          uri: lb://order-service
          predicates:
            - Path=/api/order/**
          filters:
            - OnceToken=X-Response-Token,uuid
          order: 1

        - id : user-route
          uri: lb://user-service
          predicates:
            - Path=/api/user/**
          order: 2

        - id: bingying-route
          uri: https://www.bing.com
          predicates:
            - Path=/search
            - name: Query
              args:
                param: q
                regexp: abc
      # 默认filter
      default-filters:
        - AddResponseHeader=X-Response-Red,111

    也可以采用注入配置类的方式设置。

@Configuration
public class CorsConfig {
    @Bean
    public CorsWebFilter corsFilter(){
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(new PathPatternParser());
        source.registerCorsConfiguration("/**", buildConfig());
        return new CorsWebFilter(source);
    }

    private CorsConfiguration buildConfig(){
        CorsConfiguration corsConfiguration = new CorsConfiguration();

        corsConfiguration.addAllowedOrigin("*");
        corsConfiguration.addAllowedHeader("content-type");
        corsConfiguration.addAllowedMethod("POST,GET,OPTIONS,DELETE,PUT");
        corsConfiguration.setMaxAge(3628800L);

        return corsConfiguration;
    }

}

更多推荐