Gateway网关浅析入门

2 篇文章 0 订阅

Gateway统一网关

基于WebFlux 框架实现的,而WebFlux框架底层则使用了高性能的Reactor 模式通讯框架Netty

对用户请求做身份认证、权限校验,路由到微服务,并实现负载均衡,限流

三大核心概念:Route路由,Predicate断言,Filter过滤器

引入依赖

<!--网关依赖-->
<dependency>
	<groupId>org.springframework.cloud</groupId>
	<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<!--nacos服务发现依赖-->
<dependency>
	<groupId>com.alibaba.cloud</groupId>
	<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> 
</dependency>
  • 网关搭建步骤

    创建项目,引入nacos服务发现和gateway依赖

    配置application.yml,包括服务基本信息、nacos地址、路由

  • 路由配置包括:

    路由id:路由的唯一标示

    路由目标(uri):路由的目标地址,http代表固定地址,lb代表根据服务名负载均衡(查询注册中心的服务)

    路由断言(predicates):路由断言,判断请求是否符合要求,符合则转发到路由目的地

    路由过滤器(filters):路由过滤器,处理请求或响应

  • 配置文件application.yml

server:
  port: 10010
logging:
  level:
    cn.itcast: debug
  pattern:
    dateformat: MM-dd HH:mm:ss:SSS
spring:
  application:
    name: gateway
  cloud:
    nacos:
      server-addr: nacos:8848 # nacos地址
    gateway:
      routes:
        - id: user-service # 路由标示,必须唯一
          #uri: http://127.0.0.1:8081 # 路由的目标地址 http就是固定地址
          uri: lb://userservice # 路由的目标地址
          predicates: # 路由断言,判断请求是否符合规则
            - Path=/user/** # 路径断言,判断路径是否是以/user开头,如果是则符合
          filters: # 过滤器
           - AddRequestHeader=Truth, Itcast is freaking awesome! # 添加请求头
        - id: order-service
          uri: lb://orderservice
          predicates:
            - Path=/order/**
      default-filters:
        - AddRequestHeader=Truth,Itcast is freaking awesome!

路由断言工厂Route Predicate Factory

匹配规则

名称说明示例
After是某个时间点后的请求- After=2037-01-20T17:42:47.789-07:00[America/Denver]
Before是某个时间点之前的请求- Before=2031-04-13T15:14:47.433+08:00[Asia/Shanghai]
Between是某两个时间点之前的请求- Between=2037-01-20T17:42:47.789-07:00[America/Denver], 2037-01-21T17:42:47.789-07:00[America/Denver]
Cookie请求必须包含某些cookie- Cookie=chocolate, ch.p
Header请求必须包含某些header- Header=X-Request-Id, \d+
Host请求必须是访问某个host(域名)- Host=.somehost.org,.anotherhost.org
Method请求方式必须是指定方式- Method=GET,POST
Path请求路径必须符合指定规则- Path=/red/{segment},/blue/**
Query请求参数必须包含指定参数- Query=name, Jack或者- Query=name
RemoteAddr请求者的ip必须是指定范围- RemoteAddr=192.168.1.1/24
Weight权重处理

过滤器工厂 GatewayFilterFactory

Spring提供了31种不同的路由过滤器工厂,对进入网关的请求和微服务返回的响应做处理

  • 过滤器的作用是什么?

    对路由的请求或响应做加工处理,比如添加请求头

    配置在路由下的过滤器只对当前路由的请求生效

  • defaultFilters的作用是什么?

    对所有路由都生效的过滤器

名称说明
AddRequestHeader给当前请求添加一个请求头
RemoveRequestHeader移除请求中的一个请求头
AddResponseHeader给响应结果中添加一个响应头
RemoveResponseHeader从响应结果中移除有一个响应头
RequestRateLimiter限制请求的流量

配置文件

gateway:
  routes:
    - id: user-service # 路由标示,必须唯一
    ....
    filters: # 局部过滤器
    - AddRequestHeader=Truth, test1 is freaking awesome! # 添加请求头
  default-filters: # 全局过滤器
        - AddResponseHeader=Truth,test2 is freaking awesome! # 添加响应头

自定义过滤器 GatewayFilter

GatewayFilter 将应用到单个路由或者一个分组的路由上

/**
 * 此过滤器功能为计算请求完成时间
 */
@Component
public class ServerGatewayFilter implements GatewayFilter, Ordered {
	private static final String ELAPSED_TIME_BEGIN = "Elapsed_Time_Begin";
        
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        log.info("ServerGatewayFilter filter ");
        // 设置初始时间
        exchange.getAttributes().put(ELAPSED_TIME_BEGIN, System.currentTimeMillis());
        return chain.filter(exchange).then(
                Mono.fromRunnable(() -> {
                    // 获取初始时间
                    Long startTime = exchange.getAttribute(ELAPSED_TIME_BEGIN);
                    if (startTime != null) {
                        // 计算时间差
                        System.out.println(exchange.getRequest().getURI().getRawPath() + ": " + (System.currentTimeMillis() - startTime) + "ms");
                    }
                })
        );
    }
    
    /*
    *过滤器存在优先级,order越大,优先级越低
    */
    @Override
    public int getOrder() {
        return 0;
    }
}

定义好ServerGatewayFilter以后,其需要跟Route绑定使用,不能在application.yml文件中配置使用

@Slf4j
@Configuration
public class GatewayRoutesConfiguration {
    /**
     * java 配置 server 服务路由
     * @param builder
     * @return
     */
    @Bean
    public RouteLocator routeLocator(RouteLocatorBuilder builder) {
        log.info("ServerGatewayFilter filtet........");
        return builder.routes()
                .route(r ->
                       r.path("/server/**")
                       // 去掉前缀1节
                       .filters(f -> f.stripPrefix(1))
                       // 注册自定义过滤器
                       .filters(new ServerGatewayFilter())
                       // 给定id
                       .id("user-service")
                       // 转发路由 
                       .uri("lb://cloud-discovery-server")
                ).build();
    }
}

全局过滤器 GlobalFilter

  • 全局过滤器的作用是什么?

对所有路由都生效的过滤器,并且可以自定义处理逻辑

  • 实现全局过滤器的步骤?

实现GlobalFilter接口

添加@Order注解或实现Ordered接口

编写处理逻辑

// @Order(-1)
@Component
public class AuthorizeFilter implements GlobalFilter, Ordered {
    /**
    *  处理当前请求,有必要的话通过{@link GatewayFilterChain}将请求交给下一个过滤器处理
    *
    * @param exchange 请求上下文,里面可以获取Request、Response等信息
    * @param chain 用来把请求委托给下一个过滤器 
    * @return {@code Mono<Void>} 返回标示当前过滤器业务结束
    */
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        // 1.获取请求参数
        ServerHttpRequest request = exchange.getRequest();
        MultiValueMap<String, String> params = request.getQueryParams();
        // 2.获取参数中的 authorization 参数
        String auth = params.getFirst("authorization");
        // 3.判断参数值是否等于 admin
        if ("admin".equals(auth)) {
            // 4.是,放行
            return chain.filter(exchange);
        }
        // 5.否,拦截
        // 5.1.设置状态码
        exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
        // 5.2.拦截请求
        return exchange.getResponse().setComplete();
    }

    @Override
    public int getOrder() {
        return -1;
    }
}

过滤器执行顺序

路由过滤器、defaultFilter、全局过滤器的执行顺序?

order值越小,优先级越高

当order值一样时,顺序是defaultFilter最先,然后是局部的路由过滤器,最后是全局过滤器

在这里插入图片描述

每一个过滤器都必须指定一个int类型的order值,order值越小,优先级越高,执行顺序越靠前

GlobalFilter通过实现Ordered接口,或者添加@Order注解来指定order值,由我们自己指定

路由过滤器和defaultFilter的order由Spring指定,默认是按照声明顺序从1递增。

当过滤器的order值一样时,会按照 defaultFilter > 路由过滤器 > GlobalFilter的顺序执行。

可以参考下面几个类的源码来查看:

org.springframework.cloud.gateway.route.RouteDefinitionRouteLocator#getFilters()方法是先加载defaultFilters,然后再加载某个route的filters,然后合并。

org.springframework.cloud.gateway.handler.FilteringWebHandler#handle()方法会加载全局过滤器,与前面的过滤器合并后根据order排序,组织过滤器链

网关限流

Gateway 网关 之 限流 - 参考资料
本篇文字Gateway中限流介绍的是,RequestRateLimiter是基于RedisLua脚本实现的令牌桶算法。
配置文件属性参考:RequestRateLimiterGatewayFilterFactory及内部类 Config,RateLimiter,KeyResolver 的字段

spring:
  cloud:
    gateway:
      routes:
        - id: member-demo
          uri: lb://my-member
          predcates:
            - name: Path
              args:
                - patterns=/member/**,/my-member/**
          
          filters:  
            # 配置令牌桶
            - name: RequestRateLimiter
              args:
                # 配置类:RateLimiter 实现类 RedisRateLimiter 对象
                redis-rate-limiter:
                  defaultRateLimiter:
                    defaultConfig:
                      # 每秒生成令牌个数
                      replenishRate: 1
                      # 令牌桶上线容量
                      burstCapacity: 5
 
                    # 自定义一个 keyResolver 实现 KeyResolver MyKeyResolver,注入容器,使用Spring的EL表达式读取值
                    defaultKeyResolver: '#{@myKeyResolver}'
 
  # 令牌桶使用到 Redis ,需要配置Redis连接属性
  redis:
    host: 127.0.0.1
    port: 6379
    password: xxx

自定义令牌桶规则:

just() 方法参数表示根据什么进行限流。实例中是根据主机名进行限流。参数值影响Redis

@Component
public class MyKeyResolver implements KeyResolver {
   /**
    * <String> 字符串泛型,代表令牌分给谁,可以是IP地址也可以是数字字符串,如果返回 "1",表示所有客户端一表只有一个令牌
    *
    * @param exchange
    * @return
    */
   @Override
   public Mono<String> resolve(ServerWebExchange exchange) {
      ServerHttpRequest request = exchange.getRequest();
      String remoteAddr = request.getRemoteAddress().getAddress().getHostAddress();
      // 对每个客户端IP进行限流
      return Mono.just(remoteAddr);
   }
}
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值