SpringCloud(5)--服务网关(GateWay)
MOKE 2020-07-15 AM loading 0条

服务网关

基本架构如下:

GateWay

Gateway 是在 Spring 生态系统之上构建的 API 网关服务,基于 Spring 5、Spring Boot 2 和 Project Reactor 等技术。它提供了一种简单且有效的方式来对 API 进行路由,并提供了一些强大的过滤器功能(熔断、限流、重试等)。

Gateway 的底层是基于 WebFlux 框架实现的,而webFlux底层使用netty通信(NIO)。

GateWay的特性:

  • 基于 Spring 5、Spring Boot 2 和 Project Reactor 进行构建
  • 动态路由,能够匹配任何请求属性
  • 可以对路由指定和边写 Predicate(断言)和 Filter(过滤器)
  • 集成 Hystrix 的断路器功能
  • 集成 Spring Cloud 服务发现功能
  • 请求限流功能、支持路径重写

GateWay与zuul的区别:

  • Zuul 1.x 是一个基于 Servlet 2.5 的阻塞架构,性能较差。而 2.x 版本基于 Netty 非阻塞并支持长连接,但与 Spring Cloud 目前还没整合。
  • Gateway 使用非阻塞 API,支持 WebSocket 且与 Spring 紧密集成。

相关概念

  • 路由: 路由是构建网关的基本模块,它由ID,目标URI,一系列的断言和过滤器组成,就是根据某些规则,将请求发送到指定服务上。

  • 断言: 断言用于匹配 HTTP 请求中的所有内容(请求头/请求参数),如果请求与断言相匹配则进行路由。

  • 过滤: 实现的过滤器可以在请求被路由前或者之后,对请求进行修改。


工作原理

客户端向 Gateway 发出请求,然后在 Gateway Handler Mapping 中找到与请求匹配的路由,将其发送到 Gateway Handler。Handler 再通过指定的过滤器链,然后将请求发送到实际的服务执行业务逻辑,最后返回。

过滤器链之间用虚线分开,是因为在发送请求之前或之后执行一些其他的业务逻辑:

  • 之前:参数校验、权限校验、流量监控、日志输出、协议转换等。
  • 之后:相应内容与响应头的修改、日志输出、流量监控等。

GateWay的使用

  1. 新建名称为 cloud-gateway-gateway9527 的Module

  2. pom文件

         <!--gateway-->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-gateway</artifactId>
            </dependency>
  3. 配置文件

            server:
              port: 9527
    
            spring:
              application:
                name: cloud-gateway
    
            eureka:
              instance:
                hostname: cloud-gateway-service
              client:
                register-with-eureka: true
                fetch-registry: true
                service-url:
                  defaultZone: http://eureka7001.com:7001/eureka
  4. 主启动类

            @SpringBootApplication
            @EnableEurekaClient
            public class GateWayMain9527 {
                public static void main(String[] args){
                    SpringApplication.run(GateWayMain9527.class,args);
                }
            }
  5. 针对pay模块,设置路由,修改GateWay模块(9527)的配置文件

            spring:
              application:
                name: cloud-gateway
              cloud:
                gateway:
                  routes:
                    - id: payment_routh           # 路由的 ID,没有固定规则但要求唯一
                      uri: http://localhost:8001  # 匹配后蹄冻服务的路由地址
                      predicates:
                        - Path=/payment/get/**     # 断言,路径相匹配的进行路由
                    - id: payment_routh2           # 路由的 ID,没有固定规则但要求唯一
                      uri: http://localhost:8001  # 匹配后蹄冻服务的路由地址
                      predicates:
                        - Path=/payment/lb/**     # 断言,路径相匹配的进行路由
  6. 开始测试,启动7001、8001、9527

    注:如果启动GateWay报错可能是GateWay模块引入了web和监控的starter依赖,需要移除

    访问http://localhost:9527/payment/get/31

    image-20200714165439147

  7. GateWay的网关配置,除了支持配置文件,还支持硬编码方式,使用硬编码配置GateWay:

    • 创建配置类

              @Configuration
              public class GateWayConfig {
                  @Bean
                  public RouteLocator customRouteLocator(RouteLocatorBuilder routeLocatorBuilder){
                      RouteLocatorBuilder.Builder routes = routeLocatorBuilder.routes();
                      routes.route("path_route_moke",r->r.path("/guonei")
                              .uri("http://news.baidu.com/"));
                      return routes.build();
                  }
              }
    • 然后重启服务即可


动态路由

上面的配置虽然首先了网关,但是是在配置文件中写死了要路由的地址。我们可以修改为,从注册中心获取某组微服务的地址,然后根据微服务名字进行路由。

  1. 修改GateWay模块的配置文件

            spring:
              application:
                name: cloud-gateway
              cloud:
                gateway:
                  discovery:
                    locator:
                      enabled: true              # 开启从注册中心动态创建路由的功能,利用微服务名进行路由
                  routes:
                    - id: payment_routh           # 路由的 ID,没有固定规则但要求唯一
                      # uri: http://localhost:8001  # 匹配后蹄冻服务的路由地址
                      uri: lb://cloud-payment-service
                      predicates:
                        - Path=/payment/get/**     # 断言,路径相匹配的进行路由
                    - id: payment_routh2           # 路由的 ID,没有固定规则但要求唯一
                      # uri: http://localhost:8001   # 匹配后蹄冻服务的路由地址
                      uri: lb://cloud-payment-service
                      predicates:
                        - Path=/payment/lb/**       # 断言,路径相匹配的进行路由
  2. 然后就可以启动7001,8001,8002,9527服务


Pridicate断言

我们之前在配置文件中配置了断言:

     predicates:
        - Path=/payment/get/**     # 断言,路径相匹配的进行路由

Gateway 包括许多内置的 Route Predicate 工厂,所有这些 Predicate 都与 HTTP 请求的不同属性匹配,且多个 Route Oredicate 工厂可以进行组合。之前我们配置的Path,就是由其中一种工厂创建的。断言还有以下的类型:

  • After:可以指定,只有在指定时间后,才可以路由到指定微服务,zai 指定的时间之前访问,都会报404。

    image-20200714174121265

  • before:与after类似,他说在指定时间之前的才可以访问

  • between:需要指定两个时间,在他们之间的时间才可以访问

  • cookie:只有包含某些指定cookie(key,value),的请求才可以路由

  • Header:只有包含指定请求头的请求,才可以路由

  • Host:只有指定主机的才可以访问

  • Method:只有指定请求才可以路由,比如get请求...

  • Path:只有访问指定路径,才进行路由,我们已经用过了

  • Query:必须带有请求参数才可以访问


Filter过滤器

Gateway 内置了多种路由过滤器,由 GatewayFilter 的工厂类生成,过滤器的类型可以在官网查看。

image-20200714175907362

生命周期:在请求进入路由之前,和处理请求完成,再次到达路由之前

种类:

  • GatewayFilter:单一的过滤器

  • GlobalFilter:全局过滤器

自定义过滤器

  1. 实现两个接口GlobalFilter和Ordered

            @Component
            @Slf4j
            public class MyLogGateWayFilter implements GlobalFilter,Ordered{
                @Override
                public Mono<Void> filter(ServerWebExchange serverWebExchange, GatewayFilterChain gatewayFilterChain) {
                    log.info("****come in MyLogGateWayFilter:"+new Date());
                    String uname = serverWebExchange.getRequest().getQueryParams().getFirst("uname");
                    if(uname == null){
                        log.info("****用户名为空,非法用户");
                        serverWebExchange.getResponse().setStatusCode(HttpStatus.NOT_ACCEPTABLE);
                        return serverWebExchange.getResponse().setComplete();
                    }
                    return gatewayFilterChain.filter(serverWebExchange);
                }
    
                @Override
                public int getOrder() {
                    return 0;
                }
            }
  2. 然后启动服务

    • 请求带unam参数

      image-20200714180830283

    • 请求不带参数

      image-20200714180915188

标签: SpringCloud

非特殊说明,本博所有文章均为博主原创。

评论啦~


召唤看板娘