SpringCloud(9)使用Gateway作为网关

0.Gateway与Zuul的区别

  1. Zuul 1.x是基于阻塞I/O的API Gateway
  2. Zuul 1.x基于servlet 2.5阻塞式架构,它不支持任何长链接(如Websocket)Zuul的设计理念与Nginx相似,每次I/O操作都会从工作线程中选择一个执行,请求线程被阻塞到工作线程完成,Nginx用C++实现,Zuul则使用Java实现,JVM本身第一次加载较慢,所以Zuul的性能要差一些。
  3. Zuul 2.x理念更先进,是基于Netty的异步非阻塞和支持长连接,但是spring cloud没有支持,在数据上Spring Cloud Gateway的RPS(每秒请求数)是Zuul 2.x的1.6倍
  4. Spring Cloud Gateway建立在Spring 5、Project Reactor和SpringBoot 2以上,使用非阻塞式API
  5. Spring Cloud Gateway还支持Websocket,并且与Spring密切集成,有良好的体验

1.Gateway的核心概念与工作流程

三大核心概念:

  1. Route(路由):路由是构建网关的基本模块,它由ID,目标URI,一系列断言和过滤器组成,如果断言为True,则匹配该路由
  2. Predicate(断言):开发人员可以匹配HTTP请求的所有信息(如请求头和请求参数),如果请求与断言相匹配则路由
  3. Filter(过滤):指的是Spring框架中的GatewayFilter的实例,使用过滤器,可以在请求被路由前或之后修改请求。

Gateway的工作流程:
在这里插入图片描述
客户端向Gateway发送请求,然后在Gateway Handler Mapping中找到与请求相匹配的路由,将其发送到Gateway Web Handler。

Handler在通过指定的过滤器链将请求发送到实际的服务中执行业务,然后返回。
过滤器使用虚线隔开,是因为过滤器可能会在请求发送之前(“pre”)和发送之后(“post”)执行业务逻辑。

Filter在“pre”类型的过滤器可以做,权限校验,参数校验,日志输出,流量控制,协议转换等。
在“post”诶性的过滤器可以做响应内容、响应头的修改,日志输出,流量监控等。

2.开始使用Gateway

①新建一个端口为9527的gateway项目

首先导入eureka,gateway依赖。

<dependencies>
        <!--自己的API通用类-->
        <dependency>
            <groupId>com.hht.cloud</groupId>
            <artifactId>cloud-api-commons</artifactId>
            <version>0.0.1-SNAPSHOT</version>
        </dependency>
        <!--eureka client-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
            <version>2.2.4.RELEASE</version>
        </dependency>
        <!--gateway-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-gateway</artifactId>
            <version>2.2.4.RELEASE</version>
        </dependency>
    </dependencies>

然后进行配置项目的yml配置文件,修改项目端口,并配置eureka的相关配置。

spring:
  application:
    name: cloud-gateway
server:
  port: 9527
eureka:
  instance:
    hostname: cloud-gateway-service
  client:
    service-url:
      defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka

最后在主启动类上加入**@EnableEurekaClient**注解。

②去使用gateway网关,为业务服务做路由

在gateway的项目yml配置文件中,进行routes路由规则的配置,下面只配置了一个接口的路由,可以配置多个。

cloud:
    gateway:
      routes:
        - id: payment8011_route1 #id,唯一
          uri: http://localhost:8011 #匹配后提供服务的路由地址
          predicates:
            - Path=/payment/get/** #断言,匹配规则

这里路由的是我的提供者服务中的get方法。
在这里插入图片描述
然后先开启eureka服务器,在开启provider服务,最后开启网关服务。

直接调用8011端口的提供者服务的接口,效果如下:

在这里插入图片描述

现在,我们可以通过访问localhost:9527/payment/get/{id}来调用提供者服务的接口。

在这里插入图片描述
可以看到,在我们添加过路有规则之后,我们可以通过访问gateway网关,然后网关对请求进行一个路由转发,从而隐藏真实的提供者服务地址

这是一种配置路由的方式,下面介绍另一种配置路由的方式。

③第二种配置路由的方式

新建一个配置类,然后写一个返回RouteLocator类型的方法,并注册进IOC容器中,在这个方法中配路由规则,我这里映射/baidu这个路径,然后路由到外网的百度。

@Configuration
public class RouteConfig {
    
    

    @Bean
    public RouteLocator myRoute(RouteLocatorBuilder builder){
    
    

        RouteLocatorBuilder.Builder route=builder.routes();

        RouteLocator routeBuild = route.route("route_news",
                r -> r.path("/baidu")
                        .uri("http://baidu.com")).build();

        return routeBuild;
    }
}

然后测试访问 localhost:9527/baidu 成功跳转到百度的网站。

④配置动态路由

在之前的路由配置中,已经写死了调用服务的端口号,这样写明显不合适,因为还有多台服务器没有使用,现在我们要做的就是,在网关上实现负载均衡,应用多服务器,在项目的yml配置文件中,进行以下修改,即可开启动态路由。

cloud:
    gateway:
      routes:
        - id: payment8011_route1 #id,唯一
          #uri: http://localhost:8011 #匹配后提供服务的路由地址
          uri: lb://CLOUD-PAYMENT-SERVICE #负载均衡,通过微服务id进行动态路由
          predicates:
            - Path=/payment/get/** #断言,匹配规则
      #开启从注册中心通过微服务id,动态路由
      discovery:
        locator:
          enabled: true

3.常用的Predicate(断言)

在启动项目的时候,可以看到,会自动加载多个predicateFactory,这些就是路由的各个predicate。

在这里插入图片描述
然后点到RoutePredicateFactory接口,可以看到这个接口的各个实现类,就是所支持的各个predicate断言。
在这里插入图片描述
下面对各个Predicate断言进行介绍。

Predicate 断言作用
After/Before 在指定的时间之后/之前,才能匹配(时间格式可以用ZonedDateTime类查看)
Between 在指定时间段之内,才能匹配(需指定DateTime1,DateTime2)
Cookie 访问时cookie需要带有指定的键值,才能匹配
Header 配置请求头,需要带有指定的属性和值,才能匹配
Host 指定Host的模板,Host header需要符合模板,才能匹配
Method 指定Http请求方法,GET、POST
Path 指定路径,符合后才会路由
Query
RemoteAddr 指定CIDR使指定的范围内子网可以匹配
Weight 指定组和权重,然后会根据权重百分比选择路由(例如指定两个route,都是group1,第一个权重为2,第二个为 8,那么有20%概率到第一个route,80%到第二个)

以下是配置实例

routes:
        - id: payment8011_route1 #id,唯一
          #uri: http://localhost:8011 #匹配后提供服务的路由地址
          uri: lb://CLOUD-PAYMENT-SERVICE #负载均衡,通过微服务id进行动态路由
          predicates:
            - Path=/payment/get/** #断言,匹配规则
            - After=2017-01-20T17:42:47.789-07:00[America/Denver]
            - Between=2017-01-20T17:42:47.789-07:00[America/Denver],2021-01-20T17:42:47.789-07:00[America/Denver]
            - Cookie=user,hht
            - Header=X-ID,\d+ #支持正则表达式
            - Host=**.hht.com
            - Method=GET,POST
            - RemoteAddr=192.168.1.1/24
            - Weight=group1,10

4.自定义全局Filter过滤器

要定义自己的全局filter过滤器,需要实现两个接口,一个是GlobalFilter,一个是Ordered,下面我的过滤器实现必须要有uname参数,不然则会拒绝访问。

@Component
@Slf4j
public class MyGlobalFilter implements GlobalFilter, Ordered {
    
    
    
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
    
    
        String uname = exchange.getRequest().getQueryParams().getFirst("uname");
        //当uname为null时,拒绝访问
        if (uname==null){
    
    
            log.warn("uname不能为null!!!!!!!!!!!!!");
            exchange.getResponse().setStatusCode(HttpStatus.NOT_ACCEPTABLE);
            return exchange.getResponse().setComplete();
        }
        return chain.filter(exchange);
    }

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

开启项目进行测试,首先是不带uname进行测试,在下图中可以看到,没有带上uname参数访问,会直接拒绝访问。
在这里插入图片描述
在这里插入图片描述
下面带上uname参数再次进行访问,带上uname参数后,可以看到,能够正常路由到对应服务。

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/qq_41120971/article/details/108114634
今日推荐