Spring Cloud Gateway 学习

1,838 阅读4分钟

参考:blog.csdn.net/forezp/arti…

简述

gateway作为网关,是外界访问的第一道城墙,也是整个系统流量的入口,它具有的作用如下:

  • 协议转换,路由转发
  • 流量聚合,对流量进行监控,日志输出
  • 作为整个系统的前端工程,对流量进行控制,有限流的作用
  • 作为系统的前端边界,外部流量只能通过网关才能访问系统
  • 可以在网关层做权限判断
  • 可以在网关层做缓存

客户端向SpringCloud Gateway发出请求,如果Gateway Handler Mapping 确定请求与路由匹配,则将其发送到Gateway web handler 处理,然后经过一系列的过滤器链,进行代理请求。在发出代理请求之后,收到代理服务的响应之后执行“post”过滤器逻辑。这跟zuul的处理过程很类似。在执行所有“pre”过滤器逻辑时,往往进行了鉴权、限流、日志输出等功能,以及请求头的更改、协议的转换;转发之后收到响应之后,会执行所有“post”过滤器的逻辑,在这里可以响应数据进行了修改,比如响应头、协议的转换等。

在上面的处理过程中,有一个重要的点就是讲请求和路由进行匹配,这时候就需要用到predicate,它是决定了一个请求走哪一个路由。

predicate简介

Predicate来自于java8的接口。Predicate 接受一个输入参数,返回一个布尔值结果。该接口包含多种默认方法来将Predicate组合成其他复杂的逻辑(比如:与,或,非)。可以用于接口请求参数校验、判断新老数据是否有变化需要进行更新操作。add–与、or–或、negate–非。

server:
  port: 8081
spring:
  profiles:
    active: after_route

---
spring:
  cloud:
    gateway:
      routes:
      - id: after_route
        uri: http://httpbin.org:80/get
        predicates:
        - After=2017-01-20T17:42:47.789-07:00[America/Denver]
  profiles: after_route

在上面的配置文件中,配置了服务的端口为8081,配置spring.profiles.active:after_route指定了程序的spring的启动文件为after_route文件。在application.yml再建一个配置文件,语法是三个横线,在此配置文件中通过spring.profiles来配置文件名,和spring.profiles.active一致,然后配置spring cloud gateway 相关的配置,id标签配置的是router的id,每个router都需要一个唯一的id,uri配置的是将请求路由到哪里。

predicates位于Gateway client 和 Gateway handler mapping之间,比如上述代码就是在时间2017-01-20....之后的请求都转发到指定的uri上,predicates中支持许多复杂的判断,可以看看开头的参考文章。

filter 简介

filter的作用和生命周期

由filter工作流程点,可以知道filter有着非常重要的作用,在“pre”类型的过滤器可以做参数校验、权限校验、流量监控、日志输出、协议转换等,在“post”类型的过滤器中可以做响应内容、响应头的修改,日志的输出,流量监控等。首先需要弄清一点为什么需要网关这一层,这就不得不说下filter的作用了。

作用

当我们有很多个服务时,比如下图中的user-service、goods-service、sales-service等服务,客户端请求各个服务的Api时,每个服务都需要做相同的事情,比如鉴权、限流、日志输出等。 对于这样重复的工作,有没有办法做的更好,答案是肯定的。在微服务的上一层加一个全局的权限控制、限流、日志输出的Api Gatewat服务,然后再将请求转发到具体的业务服务层。这个Api Gateway服务就是起到一个服务边界的作用,外接的请求访问系统,必须先通过网关层。

生命周期

Spring Cloud Gateway同zuul类似,有“pre”和“post”两种方式的filter。客户端的请求先经过“pre”类型的filter,然后将请求转发到具体的业务服务,比如上图中的user-service,收到业务服务的响应之后,再经过“post”类型的filter处理,最后返回响应到客户端。

自定义过滤器

Spring Cloud Gateway中内置了19种过滤器,当然我们也能自己定制过滤器


public class RequestTimeFilter implements GatewayFilter, Ordered {

    private static final Log log = LogFactory.getLog(GatewayFilter.class);
    private static final String REQUEST_TIME_BEGIN = "requestTimeBegin";
    
    /**
     * 不需要拦截的URL列表
     */
    public static final List<String> NOT_INTERCEPT = new ArrayList<>();
    
    //添加不需要拦截的url
     static {
        NOT_INTERCEPT.add("/api/user/login");
        NOT_INTERCEPT.add("/api/v2/user/user/login");
        NOT_INTERCEPT.add("/api/v2/user/dataRepair/repairRoleAuthData");
        NOT_INTERCEPT.add("/api/v2/user/license/updateDocCount");
        NOT_INTERCEPT.add("/api/user/signup");
        NOT_INTERCEPT.add("/api/user/forget-pwd");
        NOT_INTERCEPT.add("/api/user/modify-pwd");
        NOT_INTERCEPT.add("/api/user/invite-info");
        NOT_INTERCEPT.add("/api/company/config");
        NOT_INTERCEPT.add("/api/wechat/login");
        NOT_INTERCEPT.add("/api/wechat/login-redirect");
        NOT_INTERCEPT.add("/api/wechat/inner/login-redirect");
        NOT_INTERCEPT.add("/api/wechat/mobile-login-redirect");
        NOT_INTERCEPT.add("/api/wechat/inner/mobile-login-redirect");
        NOT_INTERCEPT.add("/api/chat/login-page");
        NOT_INTERCEPT.add("/api/chat/to-login-page");
        NOT_INTERCEPT.add("/api/wechat/login-url")
         
     }
        


    @Override
    
    //exchange中记录了请求的开始时间,request内容,也可以添加response等
    
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {

        exchange.getAttributes().put(REQUEST_TIME_BEGIN, System.currentTimeMillis());
        
        //chain.filter相当于放行,交给下一个filter处理
        
        return chain.filter(exchange).then(
                Mono.fromRunnable(() -> {
                    Long startTime = exchange.getAttribute(REQUEST_TIME_BEGIN);
                    if (startTime != null) {
                        log.info(exchange.getRequest().getURI().getRawPath() + ": " + (System.currentTimeMillis() - startTime) + "ms");
                    }
                })
        );

    }

    @Override
    //给过滤器设定优先级别
    public int getOrder() {
        return 0;
    }
}

filter-chain 通过 Ordered中的 getOrder 方法设置的值串联起来,值越小优先级越高。

filter中的限流

常见的限流算法有三种:

  • 计数器
  • 漏桶算法
  • 令牌桶算法

可以参考这两篇文章:

Spring Cloud Gateway 限流

Spring Cloud GateWay中的过滤器用lua脚本实现了令牌桶方式的限流,如图: