GateWay基础知识及简单应用

GateWay

API网关,就是指系统的统一入口,它封装了应用程序的内部结构,为客户端提供统一服务,一些与业务本身功能无关的公共逻辑可以在这里实现,诸如认证、鉴权、监控、路由转发等等。

官方文档地址:https://docs.spring.io/spring-cloud-gateway/docs/current/reference/html/

API网关可体统的功能举例:

  • 关注稳定与安全
    • 全局性流控
    • 日志统计
    • 防止SQL注入
    • 防止Web攻击
    • 屏蔽工具扫描
    • 黑白IP名单
    • 证书/加解密处理
  • 提供更好的服务
    • 服务级别流控
    • 服务降级与熔断
    • 路由与负载均衡、灰度策略
    • 服务过滤、聚合与发现
    • 权限验证与用户级别策略
    • 业务规则与参数校验
    • 多级缓存策略

Spring Cloud Gateway 是Spring Cloud官方推出的第二代网关框架,定位于取代 Netflix Zuul1.0。相比 Zuul 来说,Spring Cloud Gateway 提供更优秀的性能,更强大的有功能。
Spring Cloud Gateway 是由 WebFlux + Netty + Reactor 实现的响应式的 API 网关。它不能在传统的 servlet 容器中工作,也不能构建成 war 包。
Spring Cloud Gateway 旨在为微服务架构提供一种简单且有效的 API 路由的管理方式,并基于 Filter 的方式提供网关的基本功能,例如 说安全认证、监控、限流等等。

功能特征

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

核心概念

  • 路由(route) 路由是网关中最基础的部分,路由信息包括一个ID、一个目的URI、一组断言工厂、一组Filter组成。如果断言为真,则说明请求的URL和 配置的路由匹配。
  • 断言(predicates) Java8中的断言函数,SpringCloud Gateway中的断言函数类型是Spring5.0框架中的ServerWebExchange。断言函数允许开发者去定义匹配Http request中的任何信息,比如请求头和参数等。
  • 过滤器(Filter) SpringCloud Gateway中的filter分为Gateway FilIer和Global Filter。Filter可以对请求和响应进行处理。

工作原理

在这里插入图片描述

执行流程如下:

  1. Gateway Client向Gateway Server发送请求 。
  2. 请求首先会被HttpWebHandlerAdapter进行提取组装成网关上下文 。
  3. 然后网关的上下文会传递到DispatcherHandler,它负责将请求分发给RoutePredicateHandlerMapping 。
  4. RoutePredicateHandlerMapping负责路由查找,并根据路由断言判断路由是否可用 。
  5. 如果过断言成功,由FilteringWebHandler创建过滤器链并调用 。
  6. 请求会一次经过PreFilter–微服务–PostFilter的方法,最终返回响应 。

GateWay初体验

  • 构建一个SpringBoot项目

  • 导入依赖

    #父工程中已经引入的 spring cloud 其他的依赖
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-gateway</artifactId>
        <exclusions>
            <exclusion>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </exclusion>
        </exclusions>
    </dependency>
    
  • 添加配置文件

    server:
      port: 8088
    spring:
      application:
        name: api-gateway
      cloud:
        # gateway的配置
        gateway:
          # 路由规则
          routes:
            - id: order_route   # 路由的唯一标识,路由到order
              uri: http://localhost:8010   # 需要转发的地址
              # 断言规则 用于路由规则的匹配
              predicates:
                - Path=/order-serv/**
                  # http://localhost:8088/order-serv/order/add  路由到 ↓
                  # http://localhost:8010/order-serv/order/add
              filters:
                - StripPrefix=1  # 转发之前去掉一级路径 order-serv
                # http://localhost:8010/order/add
    
  • 通过GateWay访问配置的规则
    在这里插入图片描述

GateWay整合nacos

  • 添加依赖

    <dependency>
        <groupId>com.alibaba.cloud</groupId>
        <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
    </dependency>
    
  • 修改配置文件

    server:
      port: 8088
    spring:
      application:
        name: api-gateway
      cloud:
        # gateway的配置
        gateway:
          # 路由规则
          routes:
            - id: order_route   # 路由的唯一标识,路由到order
              uri: lb://order-service  # 需要转发的地址  # lb是从nacos中按照名称获取服务,并遵循负载均衡策略
              # 断言规则 用于路由规则的匹配
              predicates:
                - Path=/order-serv/**
                  # http://localhost:8088/order-serv/order/add  路由到 ↓
                  # http://localhost:8010/order-serv/order/add
              filters:
                - StripPrefix=1  # 转发之前去掉一级路径 order-serv
                # http://localhost:8010/order/add
        # 添加nacos配置信息
        nacos:
          server-addr: 192.168.2.7:8848
          discovery:
            username: nacos
            password: nacos
            namespace: public
    

断言

当请求gateway的时候, 使用断言对请求进行匹配, 如果匹配成功就路由转发, 如果匹配失败就返回404 。

内置断言工厂

  • 基于Datetime类型的断言工厂
    此类型的断言根据时间做判断,主要有三个:

    1. AfterRoutePredicateFactory: 接收一个日期参数,判断请求日期是否晚于指定日期

      - After=2017-01-20T17:42:47.789-07:00[America/Denver]
      
    2. BeforeRoutePredicateFactory: 接收一个日期参数,判断请求日期是否早于指定日期

      - Before=2017-01-20T17:42:47.789-07:00[America/Denver]
      
    3. BetweenRoutePredicateFactory: 接收两个日期参数,判断请求日期是否在指定时间段内

      - Between=2017-01-20T17:42:47.789-07:00[America/Denver], 2017-01-21T17:42:47.789-07:00[America/Denver]
      
  • 基于远程地址的断言工厂
    RemoteAddrRoutePredicateFactory:接收一个IP地址段,判断请求主机地址是否在地址段中

    ‐ RemoteAddr=192.168.1.1/24
    
  • 基于Cookie的断言工厂
    CookieRoutePredicateFactory:接收两个参数,cookie 名字和一个正则表达式。 判断请求 。 Cookie是否具有给定名称且值与正则表达式匹配。

     ‐Cookie=chocolate, ch.
    
  • 基于Header的断言工厂
    HeaderRoutePredicateFactory:接收两个参数,标题名称和正则表达式。 判断请求Header是否具有给定名称且值与正则表达式匹配。

     ‐Header=X‐Request‐Id, \d+
    
  • 基于Host的断言工厂
    HostRoutePredicateFactory:接收一个参数,主机名模式。判断请求的Host是否满足匹配规则。

     ‐Host=**.testhost.org
    
  • 基于Method请求方法的断言工厂
    MethodRoutePredicateFactory:接收一个参数,判断请求类型是否跟指定的类型匹配。

     ‐Method=GET
    
  • 基于Path请求路径的断言工厂
    PathRoutePredicateFactory:接收一个参数,判断请求的URI部分是否满足路径规则。

     ‐Path=/foo/{segment}
    
  • 基于Query请求参数的断言工厂
    QueryRoutePredicateFactory :接收两个参数,请求param和正则表达式, 判断请求参数是否具有给定名称且值与正则表达式匹配。

     ‐Query=baz, ba.
    
  • 基于路由权重的断言工厂
    WeightRoutePredicateFactory:接收一个[组名,权重], 然后对于同一个组内的路由按照权重转发。

     routes:
     ‐id: weight_route1
      uri: host1
      predicates:
     ‐Path=/product/**
     ‐Weight=group3, 1
     ‐id: weight_route2
      uri: host2
      predicates:
     ‐Path=/product/**
     ‐Weight= group3, 9
    

自定义断言工厂

  1. 自定义断言工厂必须交个spring管理
  2. 自定义断言工厂类名必须以RoutePredicateFactory结尾(约定大于配置的思想)
  3. 继承AbstractRoutePredicateFactory抽象类
  4. 自定义断言工厂内部声明静态内部类,声明属性用来接收配置文件中对应的断言信息
  5. 使用shortcutFieldOrder方法进行数据绑定
  6. 在applay内进行逻辑判断
@Component
public class MyRoutePredicateFactory extends AbstractRoutePredicateFactory<MyRoutePredicateFactory.Config> {


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

    public Predicate<ServerWebExchange> apply(Config config) {
        return new GatewayPredicate() {
            public boolean test(ServerWebExchange serverWebExchange) {
                return config.getName().equals("zhangsan");
            }

            public String toString() {
                return String.format("MyRoute: param=%s", config.getName());
            }
        };
    }

    public List<String> shortcutFieldOrder() {
        return Collections.singletonList("name");
    }

    public static class Config{
        private String name;

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }
    }
}

过滤器

内置过滤器

Gateway 内置了很多的过滤器工厂,我们通过一些过滤器工厂可以进行一些业务逻辑处理器,比如添加剔除响应头,添加去除参数等。

官网中的过滤器都有示例,可参考官网

https://docs.spring.io/spring-cloud-gateway/docs/2.2.5.RELEASE/reference/html/#gatewayfilter-factories

过滤器工厂作用参数
AddRequestHeader为原始请求添加HeaderHeader的名称及值
AddRequestParameter为原始请求添加请求参数参数名称及值
AddResponseHeader为原始响应添加HeaderHeader的名称及值
DedupeResponseHeader剔除响应头中重复的值需要去重的Header名称及去重策略
Hystrix为路由引入Hystrix的断路器保护HystrixCommand 的名称
FallbackHeaders为fallbackUri的请求头中添加具体的异常信息Header的名称
PrefixPath为原始请求路径添加前缀前缀路径
PreserveHostHeader为请求添加一个preserveHostHeader=true 的 属性,路由过滤器会检查该属性以决定是否要发送原始的Host
RequestRateLimiter用于对请求限流,限流算法为令牌桶keyResolver、rateLimiter、statusCode、denyEmptyKey、emptyKeyStatus
RedirectTo将原始请求重定向到指定的URLhttp状态码及重定向的url
RemoveHopByHopHeadersFilter为原始请求删除IETF组织规定的一系列Header默认就会启用,可以通过配置指定仅删除哪些Header
RemoveRequestHeader为原始请求删除某个HeaderHeader名称
RemoveResponseHeader为原始响应删除某个HeaderHeader名称
RewritePath重写原始的请求路径原始路径正则表达式以及重写后路径的正则表达式
RewriteResponseHeader重写原始响应中的某个HeaderHeader名称,值的正 则表达式,重写后的值
SaveSession在转发请求之前,强制执行WebSession::save 操作
SecureHeaders为原始响应添加一系列起安全作用的响应头无,支持修改这些安全响应头的值
SetPath修改原始的请求路径修改后的路径
SetResponseHeader修改原始响应中某个Header的值Header名称,修改后的值
SetStatus修改原始响应的状态码HTTP 状态码,可以是数字,也可以是字符串
StripPrefix用于截断原始请求的路径使用数字表示要截断的路径的数量
Retry针对不同的响应进行重试retries、statuses、methods、series
RequestSize设置允许接收最大请求包的大小。如果请求包大小超过设置的值,则返回 413 Payload Too Large请求包大小,单位为字节,默认值为5M
ModifyRequestBody在转发请求之前修改原始请求体内容修改后的请求体内容
ModifyResponseBody修改原始响应体的内容修改后的响应体内容

自定义过滤器

自定义的过滤器和前面的自定义断言工厂流程差不多。

自定义过滤器对响应头进行了添加,MyGatewayFilter:test filter

代码如下:

@Component
public class MyGatewayFilterFactory extends AbstractGatewayFilterFactory<MyGatewayFilterFactory.MyConfig> {

    public MyGatewayFilterFactory() {
        super(MyGatewayFilterFactory.MyConfig.class);
    }

    @Override
    public GatewayFilter apply(MyConfig config) {
        return new GatewayFilter() {
            @Override
            public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
                String name = exchange.getRequest().getQueryParams().getFirst("name");
                if(StringUtils.isNotBlank(name)){
                    if (config.getValue().equals(name)){
                        exchange.getResponse().getHeaders().set("MyGatewayFilter","test filter");
                        return chain.filter(exchange);
                    }else{
                        exchange.getResponse().setStatusCode(HttpStatus.NOT_FOUND);
                        exchange.getResponse().setComplete();
                    }
                }
                //正常请求
                return chain.filter(exchange);
            }
        };
    }

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

    public static class MyConfig{
        private String value;
        private String key;

        public String getValue() {
            return value;
        }

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

        public String getKey() {
            return key;
        }

        public void setKey(String key) {
            this.key = key;
        }
    }
}

配置文件如下:

server:
  port: 8088
spring:
  application:
    name: api-gateway
  cloud:
    gateway:
      routes:
        - id: order_route
          uri: lb://order-service
          predicates:
            - Path=/order-serv/**
            - My=zhangsan
          filters:
            - My=zhangsan
            - StripPrefix=1
    nacos:
      server-addr: 192.168.2.7:8848
      discovery:
        username: nacos
        password: nacos
        namespace: public

查看效果:
在这里插入图片描述

全局过滤器

局部过滤器和全局过滤器的区别:

GlobalFilter接口和GatewayFilter 有一样的接口定义,但GlobalFilter 会作用于所有路由。

局部:针对某个路由,需要在所应用的路由中进行配置。

全局:针对所有路由请求,一旦定义就可以生效。

Gateway自带内置全局过滤器

在这里插入图片描述

自定义全局过滤器

实现GlobalFilter接口即可;

@Component
public class MyGlobalLogFilter implements GlobalFilter {

    Logger log = LoggerFactory.getLogger(this.getClass());

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        log.info("访问路径为{}",exchange.getRequest().getPath().value());
        return chain.filter(exchange);
    }
}

在这里插入图片描述

Gateway整合sentinel

网关限流官方文档

  • 添加依赖

    <dependency>
        <groupId>com.alibaba.cloud</groupId>
        <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
    </dependency>
    
    <dependency>
        <groupId>com.alibaba.cloud</groupId>
        <artifactId>spring-cloud-alibaba-sentinel-gateway</artifactId>
    </dependency>
    
  • 添加配置文件

        sentinel:
          transport:
            dashboard: 127.0.0.1:8080
    
  • 启动项目、nacos、sentinel

  • 查看效果
    在这里插入图片描述

这个控制台和单纯的项目整合sentinel的页面有一些不一样的地方,大配置基本大同小异。一些流控规则可以参考我sentinel笔记

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值