目录

前言

一、什么是GateWay?

1.1 GateWay的核心概念

1.2 GateWay的工作过程 

二、创建网关

1.引入库

三、网关过滤器

3.1 网关实现黑白名单鉴权

总结


前言

  在使用Spring Cloud全家桶构建微服务的时候一定会使用到网关,可使用的网关有Netflix Zuul,Spring Cloud Gateway。相比于Zuul,gateway是使用基于高性能的Reactor模式响应式通信框架Netty,异步非阻塞模型的WebFlux来进行网络通信的。gateway的性能要高于Zuul,官方测试,gateway是zuul的1.6倍,旨在为微服务架构提供统一种简单有效的统一的路由处理方式。

  gateway不仅提供统一的路由方式,并且基于Filter链的方式提供了网关的基本功能,例如鉴权、流量控制、熔断、路径重写、日志监控等。这篇文章就从搭建一个网关并且进行配置来实现网关的这些功能来熟悉gateway网关。


一、什么是GateWay?

1.1 GateWay的核心概念

  • 个 ID 、⼀个⽬标 URL (最终路由到的地址)、⼀系列的断⾔(匹配条件判断)和 Filter 过滤器(精细化控制)组成。如果断⾔为 true ,则匹配该路由
  • Java8 中的断⾔ java.util.function.Predicate ,开发
    ⼈员可以匹配 Http 请求中的所有内容(包括请求头、请求参数等)(类似于 nginx 中的 location 匹配⼀样),如果断⾔与请求相匹配则路由。
  • ⼀个标准的 Spring webFilter ,使⽤过滤器,可以在请求之前
    或者之后执⾏业务逻辑。

1.2 GateWay的工作过程 

spring gateway 路由调优 springcloud gateway 路由_spring


  客户端向 Spring Cloud GateWay 发出请求,然后在 GateWay Handler Mapping 中


找到与请求相匹配的路由,将其发送到 GateWay Web Handler ; Handler 再通过指


定的过滤器链来将请求发送到我们实际的服务执⾏业务逻辑,然后返回。过滤器之


间⽤虚线分开是因为过滤器可能会在发送代理请求之前( pre )或者之后( post )执


⾏业务逻辑。


  Filter 在 “pre” 类型过滤器中可以做参数校验、权限校验、流量监控、⽇志输出、协议


转换等,在 “post” 类型的过滤器中可以做响应内容、响应头的修改、⽇志的输出、流


量监控等


二、创建网关

1.引入库

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

在pom文件种添加了这些依赖之后,启动项目就是一个网关系统了,如果引入了依赖但是不想该项目作为网关系统则可以添加配置spring.cloud.gateway.enabled=false则不会作为网关。

  在配置文件中添加配置

server:
  port: 8089
spring:
  application:
    name: api-gateway
  cloud:
    gateway:
      routes: # 路由可以有多个
        - id: service1  #自定义的路由ID,必须保持唯一
          uri: http://127.0.0.1:8080  #目标服务地址
          predicates:  # 断言,路由的条件,对请求进行过滤
            - Path=/wx/**

 配置完之后,启动项目,请求接口http://127.0.0.1:8089/wx/login则会被路由到http://127.0.0.1:8080/wx/login。至此路由配置成功。

三、网关过滤器

3.1 网关实现黑白名单鉴权

第一步创建一个Filter

@Component
public class BlackListFilter  implements GlobalFilter, Ordered {

    private static final Logger log = LoggerFactory.getLogger(BlackListFilter.class);

    // 项目中使用的时候应该配置在redis或者配置中心
    private static List<String> blackList = new ArrayList<>();
    static {
        blackList.add("127.0.0.1"); // 模拟本机地址
    }

    /**
     *
     * @param exchange
     * @param chain
     * @return
     */
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        // 思路:获取客户端ip,判断是否在⿊名单中,在的话就拒绝访问,不在的话就放⾏
        // 从上下⽂中取出request和response对象
        ServerHttpRequest request = exchange.getRequest();
        ServerHttpResponse response = exchange.getResponse();
        // 从request对象中获取客户端ip
        String clientIp =
                request.getRemoteAddress().getHostString();
        // 拿着clientIp去⿊名单中查询,存在的话就决绝访问
        if(blackList.contains(clientIp)) {
            // 决绝访问,返回
            response.setStatusCode(HttpStatus.UNAUTHORIZED); // 状态码
            log.debug("=====>IP:" + clientIp + " 在⿊名单中,将被拒绝访 问!");
            String data = "请求IP在黑名单中,请求被拦截!";
            DataBuffer wrap =
                    response.bufferFactory().wrap(data.getBytes());
            return response.writeWith(Mono.just(wrap));
        }
        // 合法请求,放⾏,执⾏后续的过滤器
        return chain.filter(exchange);
    }

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

这个filter里面对客户端的ip进行黑白名单鉴定,如果在黑名单中则拦截。

3.2 网关限流

有一篇文章写的特别详细,可以参考

GatWay目前默认的只有基于redis的请求频率限流,所以要实现限流需要先启动redis服务。下面就是基于redis的GatWay默认的分布式的请求频率限流的实现

添加依赖

<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-data-redis-reactive</artifactId>
</dependency>

1. 在配置文件中添加配置

server:
  port: 8089
logging:
  level:
    root: debug
spring:
  application:
    name: api-gateway
  cloud:
    gateway:
      routes:
        - id: service1
          uri: http://127.0.0.1:8080
          predicates:
            - Path=/wx/**
          filters:
            - name: RequestRateLimiter
              args:
                # 令牌桶填充的速率 秒为单位
                redis-rate-limiter.replenishRate: 1
                # 令牌桶总容量
                redis-rate-limiter.burstCapacity: 3
                # 作为限流的key
                key-resolver: "#{@ipKeyResolver}"
  redis:
    host: 192.168.206.108
    database: 0
    port: 6379

2. 创建限流的对象key

/**
     * ip限流
     * @return
     */
    @Bean
    public KeyResolver ipKeyResolver() {
        return exchange -> Mono.just(exchange.getRequest().getRemoteAddress().getHostName());
    }

通过这两个简单的配置就完成限流了,按照配置,当前最大能处理突发的每秒3个请求,否则按照每秒处理一个请求。

查看GateWay的官网(GateWay官网)发现,GateWay实现限流的实现是通过RequestRateLimiterGateWayFilterFactor去调用实现了RateLimiter的实现类来对请求进行限流的。

spring gateway 路由调优 springcloud gateway 路由_分布式_02


可以自己定义一个类,并实现RateLimiter接口,然后通过SpEL表达式去指点这个类作为限流的实现类,就可以实现自己定义限流算法。

1. 定义一个限流算法类

spring gateway 路由调优 springcloud gateway 路由_分布式_03

 其中最重要的式isAllowed方法中设置response中的allowed参数,如果是true就放行,false则进行限流。

2. 修改配置文件

spring gateway 路由调优 springcloud gateway 路由_spring_04

 

这就会使用自己定义的限流算法了。 

3.3 网关熔断

添加依赖

...
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-circuitbreaker-reactor-resilience4j</artifactId>
</dependency>
...

   1、添加配置

server:
  port: 8089
logging:
  level:
    root: debug
spring:
  application:
    name: api-gateway
  cloud:
    gateway:
      routes:
        - id: service1
          uri: http://127.0.0.1:8080
          predicates:
            - Path=/wx/**
          filters:
            - name: CircuitBreaker
              args:
                name: myCircuitBreaker
                fallbackUri: forward:/fallback

2、增加一个熔断之后的回调方法

@RequestMapping("/fallback")
    public Mono<String> fallback() {
        return Mono.just("fallback");
    }

总结

  文章主要叙述了怎么搭建一个GateWay网关,以及如何实现GateWay的鉴权、限流、熔断等功能,GateWay还有各种强大的功能,如果需要了解可以直接去官网(GateWay官网)。本文说到了自定义限流,这里涉及一些限流算法,但是没有展开说明,以后有时间会专门针对限流算法写一篇博客。