SpringCloud --- gateway

介绍

zuul是Netflix开发的一套不错的网关,但是也有着一定的缺陷,目前Netflix 对着zuul2.0开始了开发;但是随着Netflix 开始对旗下很多微服务组件开始停更以后,zuul2.0以后也可能面临着停更的风险;在此基础上 spring推出了比较优秀的一款框架 – gateway;其目标是为了替换zuul,成为新一代的网关;

Spring Cloud Gateway 可以看做是一个 Zuul 1.x 的升级版和代替品,比 Zuul 2 更早的使用 Netty 实现异步 IO,从而实现了一个简单、比 Zuul 1.x 更高效的、与 Spring Cloud 紧密配合的 API 网关。
Spring Cloud Gateway 里明确的区分了 Router 和 Filter,并且一个很大的特点是内置了非常多的开箱即用功能,并且都可以通过 SpringBoot 配置或者手工编码链式调用来使用。

比如内置了 10 种 Router,使得我们可以直接配置一下就可以随心所欲的根据 Header、或者 Path、或者 Host、或者 Query 来做路由。

比如区分了一般的 Filter 和全局 Filter,内置了 20 种 Filter 和 9 种全局 Filter,也都可以直接用。当然自定义 Filter 也非常方便。

搭建环境

  1. 创建maven工程

  2. 导入pom依赖

    <dependencies>
        <!--gateway依赖-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-gateway</artifactId>
        </dependency>
        <!--eureka依赖-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
    </dependencies>
  1. 创建启动器
@SpringBootApplication
@EnableDiscoveryClient//成为注册中心服务
public class GatewayApplication {
    public static void main(String[] args) {
        SpringApplication.run(GatewayApplication.class, args);
    }
}
  1. 修改配置文件
server:
  port: 9999
spring:
  application:
    name: gateway-server # 应用名称,会在Eureka中作为服务的id标识(serviceId)
  cloud:
    gateway:
      routes:
        - id: user-service #路由的ID,没有固定规则但要求唯一,建议配合服务名
          uri: lb://user-service    #匹配后提供服务的路由地址,lb指的是从注册中心中获取对应服务名称的ip地址
          predicates:
            - Path=/user/**   #断言,路径相匹配的进行路由
eureka:
  client:
    service-url:
      defaultZone: http://127.0.0.1:10086/eureka

注:网关可以配置真实的url地址的,但是这样维护比较麻烦,所以一般都是通过注册中心来获取配置信息

  1. 测试
    在这里插入图片描述
    这里跟zuul的不同,zuul是在端口号后面加上设置的 后缀,在转发的;这里在端口号中直接加你访问的端口号,之后路由匹配规则后转发的

gateway功能

gateway有个强大的几个功能

  • Route(路由):这是网关的基本构建模块。它由一个ID,一个目标url,一组断言和一组过滤器定义。如果断言是真,则路由匹配
  • Predicate(断言):输入类型是一个ServerWebExchange。我们可以使用它来匹配来自Http请求的任务内容,例如Headers或参数
  • Filter(过滤器):Gateway中的filter分为两种类型的Filter,分别是GatewayFilter和Global Filter。这种过滤器Filter将会对请求和响应进行修改处理

路由

路由和断言是gateway的一个特色,路由的转发,会根据匹配到断言设置的,转发,这里gateway的配置有两种,一种是配置文件中配置,一种是代码配置

配置文件配置

server:
  port: 10001
spring:
  application:
    name: gateway-server # 应用名称,会在Eureka中作为服务的id标识(serviceId)
  cloud:
    gateway:
      routes:
      - id: user-service #路由的ID,没有固定规则但要求唯一,建议配合服务名
        uri: lb://user-service    #匹配后提供服务的路由地址
        order: -1
        predicates:
          - Path=/user/**   #断言,路径相匹配的进行路由

在配置文件中配置的话,就是按照我们原来案例中来配置的

代码配置

在代码中配置的话,是利用springboot的配置文件的方法来实现配置

@Configuration
public class GateWayConfig {

    @Bean
    public RouteLocator customRouteLocator(RouteLocatorBuilder routeLocatorBuilder) {
        RouteLocatorBuilder.Builder routes = routeLocatorBuilder.routes();
        //第一个 user-service2 对应使用的id
        //第二个对应路径
        //第三个对应url
        routes.route("user-service2", r -> r.path("/ace/**").uri("lb://user-service")).build();
        return routes.build();
    }
}

断言

在配置路由的时候我们发现了,gateway是根据匹配到的规则来转发的;但是gateway配置的规则不只是有路径,还有其他
在这里插入图片描述

配置文件实现

server:
  port: 10001
spring:
  application:
    name: gateway-server # 应用名称,会在Eureka中作为服务的id标识(serviceId)
  cloud:
    gateway:
      routes:
      - id: user-service #路由的ID,没有固定规则但要求唯一,建议配合服务名
        uri: lb://user-service    #匹配后提供服务的路由地址
        order: -1
        predicates:
          - Path=/user/**   #断言,路径相匹配的进行路由
          - Host=**.foo.org #通过hsot匹配接收一组参数,一组匹配的域名列表,这个模板是一个 ant 分隔的模板,用.号作为分隔符。它通过参数中的主机地址作为匹配规则。
          - Cookie=ityouknow, kee #一个是 Cookie name , 一个是正则表达式,路由规则会通过获取对应的 Cookie name 值和正则表达式去匹配,如果匹配上就会执行路由,如果没有匹配上则不执行。--cookie "ityouknow=kee"
          - Path=/headers #断言,路径相匹配的进行路由
          - Method=GET # 通过请求方式匹配
          - Header=X-Request-Id, \d+ # 通过请求头中的参数来匹配 第一个是属性  第二个是属性值
          - Query=foo, ba. # 通过请求参数属性匹配  包含 keep 属性并且参数值是以 pu 开头的长度为三位的字符串才会进行匹配和路由。 例如localhost:8080?keep=pub
          - Query=baz  # 通过请求参数属性匹配 必须有 含有的参数
          - After=2018-01-20T06:06:06+08:00[Asia/Shanghai] # 时间配置 在这个时间之后才会进入
          - RemoteAddr=192.168.1.1/24 # 根据id地址匹配

注:在代码中实现的话,将r.path()更换为其他的方式匹配即可

    @Bean
    public RouteLocator customRouteLocator(RouteLocatorBuilder routeLocatorBuilder) {
        RouteLocatorBuilder.Builder routes = routeLocatorBuilder.routes();
        //第一个 user-service2 对应使用的id
        //第二个对应路径
        //第三个对应url
        routes.route("user-service2",
                r -> r.path("/ace/**").uri("lb://user-service")).build();
        return routes.build();
    }

过滤器

  1. 生命周期
    gateway的生命周期比zuul的就简单很多了,跟普通的过滤器相同,两种在
  • pre 在业务逻辑之前
  • post 在业务逻辑之后
  1. 种类
    种类为为两种
  • 单一 GatewayFilter
  • 全局 GlobaFilter
  1. 实现
  • 配置文件实现
spring:
  application:
    name: gateway-application
  cloud:
    # Spring Cloud Gateway 配置项,对应 GatewayProperties 类
    gateway:
      # 路由配置项,对应 RouteDefinition 数组
      routes:
        - id: user-service # 路由的编号
          uri: lb://user-service # 路由到的目标地址,只能到域名部分 https://blog.csdn.net/dear_little_bear
          predicates: # 断言,作为路由的匹配条件,对应 RouteDefinition 数组
            - Path=/user/**
          filters:
            - StripPrefix=1
            - AddRequestHeader=X-Request-red, blue # 请求头的属性和属性值

  • 代码实现
    全局拦截器
@Component
@Slf4j
public class MyLogGateWayFilter implements GatewayFilter, Ordered {
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {

        log.info("*********come in MyLogGateWayFilter: "+new Date());
        //从上下文中请求头查询到
        String username = exchange.getRequest().getQueryParams().getFirst("username");
        if(StringUtils.isEmpty(username)){
            log.info("*****用户名为Null 非法用户,(┬_┬)");
            //根据上下文回应
            exchange.getResponse().setStatusCode(HttpStatus.NOT_ACCEPTABLE);//给人家一个回应
            return exchange.getResponse().setComplete();
        }
        return chain.filter(exchange);
    }

    @Override
    //返回拦截器的优先级
    public int getOrder() {
        return 0;
    }
}

单一拦截器

@Component
public class CsdnRequestFilter implements GatewayFilter, Ordered {

    @Value("${gateway.csdn.PaaSID}")
    private String paaSID;

    @Value("${gateway.csdn.PaaSToken}")
    private String paaSToken;

    @Value("${gateway.csdn.nonce}")
    private String nonce;

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        String timeTamp = String.valueOf(System.currentTimeMillis() / 1000);
        String signature = SecureUtil.sha256(timeTamp + nonce + paaSToken);
        System.out.print("自定义过滤器:timeTamp:"+timeTamp+";signature:"+signature);
        //提取应用账户及应用令牌,鉴权
        ServerHttpRequest request = exchange.getRequest().mutate()
                .header("x-tif-nonce", nonce)
                .header("x-tif-signature", signature)
                .header("x-tif-paasid", paaSID)
                .header("x-tif-timestamp", timeTamp)
                .build();

        return chain.filter(exchange.mutate().request(request).build());
    }

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

这是继承实现后,需要在代码实现的路由器中配置

        return builder.routes()
                .route(r -> r.path("/csdn3/**")
                        .filters(f->f.stripPrefix(1)
                                .filter(csdnRequestFilter))
                        .uri(csdnHost)
                        .order(3))
                .build();

总结

Zuul:

使用的是阻塞式的 API,不支持长连接,比如 websockets。

底层是servlet,Zuul处理的是http请求

没有提供异步支持,流控等均由hystrix支持。

依赖包spring-cloud-starter-netflix-zuul。

Gateway:

底层依然是servlet,但使用了webflux,多嵌套了一层框架

依赖spring-boot-starter-webflux和/ spring-cloud-starter-gateway

提供了异步支持,提供了抽象负载均衡,提供了抽象流控,并默认实现了RedisRateLimiter。

相同点:
1、底层都是servlet

2、两者均是web网关,处理的是http请求

不同点:

1、内部实现:

gateway对比zuul多依赖了spring-webflux,在spring的支持下,功能更强大,内部实现了限流、负载均衡等,扩展性也更强,但同时也限制了仅适合于Spring Cloud套件
  zuul则可以扩展至其他微服务框架中,其内部没有实现限流、负载均衡等。
2、是否支持异步
  zuul仅支持同步
  gateway支持异步。理论上gateway则更适合于提高系统吞吐量(但不一定能有更好的性能),最终性能还需要通过严密的压测来决定
3、框架设计的角度
  gateway具有更好的扩展性,并且其已经发布了2.0.0的RELESE版本,稳定性也是非常好的
4、性能
  WebFlux 模块的名称是 spring-webflux,名称中的 Flux 来源于 Reactor 中的类 Flux。Spring webflux 有一个全新的非堵塞的函数式 Reactive Web 框架,可以用来构建异步的、非堵塞的、事件驱动的服务,在伸缩性方面表现非常好。使用非阻塞API。 Websockets得到支持,并且由于它与Spring紧密集成,所以将会是一个更好的 开发 体验。
  Zuul 1.x,是一个基于阻塞io的API Gateway。Zuul已经发布了Zuul 2.x,基于Netty,也是非阻塞的,支持长连接,但Spring Cloud暂时还没有整合计划。

总结
  总的来说,在微服务架构,如果使用了Spring Cloud生态的基础组件,则Spring Cloud Gateway相比而言更加具备优势,单从流式编程+支持异步上就足以让开发者选择它了。
  对于小型微服务架构或是复杂架构(不仅包括微服务应用还有其他非Spring Cloud服务节点),zuul也是一个不错的选择。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值