微服务之服务网关Gateway

一、什么是Gateway?

  Gateway是Spring生产系统上构建的API服务网关,基于Spring5、SpringBoot2和ProjectReactor等技术。它的目标是提供一种简单有效的方式对API进行路由,以及提供一些强大的过滤器功能,包括熔断、限流、重试等。

  SpringCloud Gateway是SpringCloud的一个全新项目,基于WebFlux框架实现的,而webFlux底层使用了高性能的Reactor模式通信框架Netty。SpringCloud Gateway为微服务架构提供一种简单有效的统一的API路由管理方式,目的是为了替代Zuul成为全新一代的服务网关。

  前面提到了服务网关,那什么又是服务网关呢?它是一个网络关口、通道,是整个微服务平台所有请求的统一入口,所有的客户端和服务消费端都只能通过这个关口来访问微服务。除了作为统一入口之外,它还可以处理非业务功能,承担认证授权、访问控制、路由、负载均衡、日志、缓存、映射、过滤、熔断、注册、服务编排、API管理、监控、统计分析等职责。所以选择一个优秀的服务网关对于开发微服务体系系统至关重要。以下是借鉴某伙伴的服务架构图:

微服务之服务网关Gateway

 

 二、Gateway的工作流程

  要理解工作流程,先了解以下三个核心名词

    1、Route路由:路由是构建网关的基本模块,由一系列的断言和过滤器组成,如果断言为true则匹配该路由。

    2、predicate断言:预先设置的规则条件。开发人员可以匹配http请求中的内容,如果请求与断言相匹配则进行路由匹配。

    3、Filte过滤器:过滤器是GatewayFilter的一个实例,它可以在请求被路由前后完成对请求的修改。Gateway中存在一系列过滤链,用于完成不同的处理(请求前可以做权限校验、流量监控、日志输出、协议转换等,请求后响应内容修改等)。

  一个web请求进来,Gateway首先会进行条件匹配,定位真正的服务节点,并在转发web请求的前后进行一些额外的处理,这些处理就通过过滤器来实现,而前面的匹配就是通过断言来实现。以下是网关内部的工作流程图

微服务之服务网关Gateway

  三、服务网关模块的搭建

  搭建服务网关模块的步骤:

  1、引入jar包:除了引入gateway的jar包外,网关本身也是一种微服务,也需要注册到服务注册中心,因此还需要引入相应的注册中心客户端jar包,进行相应的配置(配置方式参考服务注册中心相关文档)。最后要注意的是,作为网关的模块请不要引入

与spring-boot-starter-web相关的包,否则会出现冲突报错。

<dependency>
  <groupId>org.springframework.cloud</groupId>
  <artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>

   2、修改application.yml文件,配置网关路由规则。路由是多个,可以配置在routes节点下,如图所示表示配置了两个路由规则: 

server:
  port: 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/** #断言,路径相匹配的进行路由

   当进行上述配置后,我们就可以不直接访问http://localhost:8001/payment/get/来调用微服务,而是通过http://localhost:9527/payment/get/来间接调用8001微服务。当客户端访问http://localhost:9527/****/***时,网关服务模块就根据路由规则进行匹配,从而调用不同的微服务(网关服务模块获取到请求地址后,用请求地址去断言,断言uri指定的微服务下是否存在predicates指定的路径模式,如果为true则调用)。

   3、完成以上两步,启动网关服务模块,客户端向微服务的请求全部通过访问该服务来实现,到此简单的网关服务模块搭建完成。

  除了2中配置文件实现路由配置的方式外,还可以通过硬编码的方式(代码中注入RouteLocator的Bean)来实现路由匹配:新建网关配置文件GatewayConfig类,写入如下类似代码即可

@Configuration
public class GatewayConfig
{ @Bean public RouteLocator customRouteLocator(RouteLocatorBuilder routeLocatorBuilder)
{ RouteLocatorBuilder.Builder routes = routeLocatorBuilder.routes();
routes.route(
id: "path_route_name", r -> r.path("/aaaa").uri("http://xxx.com/bbbb") /* /aaaa路径将会被路由到http://xxx.com/bbbb */
).build();
  return routes.build();
}

 四、动态路由配置

  默认情况下,Gateway会根据注册中心注册的服务列表,以微服务的名称为路径创建动态路由进行转发,实现动态路由功能。开启动态路由只需要在上述简单路由的基础上修改yml配置文件,开启动态路由功能即可,要注意创建动态路由时uri要写成服务名称的形式,如下所示:

server:
  port: 9527

spring:
  application:
     name: cloud-gateway
  cloud:
     gateway:
discovery:
locator :
enabled: true #开启从注册中心动态创建路由的功能,利用微服务名进行路由
routes:
           - id: payment_routh                     #路由的ID,没有固定规则但要求唯一,建议配合服务名
             uri: http://cloud-server-name         #这里写微服务的名称,不要用地址
             predicates:  
- Path=/payment/get/** #断言,路径相匹配的进行路由

 五、Gateway过滤器Filter

  过滤器允许以某种方式修改传入的HTTP请求或返回的HTTP响应。过滤器作用于某些特定路由。Spring Cloud Gateway包括许多内置的 Filter工厂,这些工厂负责创建Filter过滤器实例,同时也支持自定义过滤器。多个过滤器结合使用可以形成过滤器链对http请求进行处理。

  1、内置的过滤器:分为单一过滤器GatewayFilter和全局过滤器GlobalFilter,作用于业务逻辑之前或业务逻辑之后。使用方式与断言类似,通过配置实现过滤功能,yml配置参考代码如下

server:
  port: 9527

spring:
  application:
     name: cloud-gateway
  cloud:
     gateway:
        discovery:
           locator :
             enabled: true 
        routes:
           - id: payment_routh                     
             uri: http://cloud-server-name         
filters:
- AddRequestParameter=X-Request-Id,1024 #过搪器工厂会在匹配的请求头加上一对请求头,名称为X-Request-Id值为1024
predicates:
- Path=/payment/get/**

    2、自定义全局过滤器:新建MyGatewayFilter类,实现GlobalFilter,Orderd接口,重写filter方法和getOrder方法,参考代码如下

@Component
public class MyGatewayFilter implements GlobalFilter,ordered  /*实现接口*/
{
    @override
     public Mono<Void> filter(ServerwebExchange exchange,GatewayFilterchain chain) /*exchange是请求的上下文,chain表示下一过滤器*/
{ string uname = exchange.getRequest().getQueryParams( ).getFirst( key: "uname");
if(uname == nul1) { exchange.getResponse().setstatuscode(Httpstatus.NOT_ACCEPTABLE);
return exchange.getResponse().setcomplete(); /*如果uname为空,则设置状态为不被接受,然后返回结果*/ } return chain.filter(exchange); /*继续执行下一过滤器*/ } @Override public int getorder()
{ return 0; /*设置过滤器顺序*/
}
}

   以上代码的作用是过滤非法用户,只需完成以上编码,无需额外配置即可实现全局过滤功能。内置的过滤器此处不再详述。

六、Gateway常用的断言Predicate

  分析前面的yml配置文件,发现predicates是复数形式,表明我们可以设置多个断言,进行更精确的匹配。Gateway提供了如下几种断言规则:

规则 配置格式 说明
After

- After=2020-02-05T15:10:03.685+08:00[Asia/Shanghai]

匹配在此时间之后的访问
Before - Before=2020-02-05T15:10:03.685+08:00[Asia/Shanghai] 匹配在此时间之前的访问
Between - Between=2020-02-05T15:10:03.685+08:00[Asia/Shanghai], 2020-02-05T15:10:03.685+08:00[Asia/Shanghai] 匹配在该时间段的访问
Cookie - Cookie=username,zhangsan 匹配cookie名称为zhangsan
Header - Header=X-Request-Id,\d+ 匹配请求头要有x-Request-Id属性并且值为整数
Host - Host=**.yy.com 匹配主机名为.yy.com
Method - Method=Get 匹配get请求
Path - Path=/payment/get/** 匹配路径
Query - Query=username,\d+ 匹配查询字符串存在username并且值为整数
RemoteAddr - RemoteAddr =192.168.0.1/16 匹配Remote Adress为192.168.0.1

 

上一篇:Gateway Webflux过滤器修改响应


下一篇:Gateway