Spring Could系列(四):微服务网关--Spring Could Gateway

Spring Could新一代网关—Spring Cloud Gateway

一、Gateway的概述

依据官网说法:Spring Cloud Gateway旨在提供一种简单而有效的方法来路由到 ApI,并提供交叉切割问题,例如:安全性、监控/指标和弹性。简单理解其实它是,我们访问微服务的一个道大门,负责处理一些路由,类似于医院大厅的质询台,指引我们具体的科室,当然也可以判断改路由是否符合断言,是否允许通过,其实也是保安加咨询。
可以看微服务的架构图,了解它扮演的角色:
在这里插入图片描述

二、Gateway的功能(特点)
  • 建立在Spring 5,响应式编程以及Spring boot 2.x上
  • 动态路由:能够匹配任何请求属性
  • 用断言和过滤来特定于路由(每一个路由可以有相应的断言和过滤器)
  • 集成了断路器(可以实现相关的断路器的功能)
  • 集成了服务发现DiscoveryClient
  • 提供可有轻松书写断言和过滤器
  • 请求频率的限制(限流)
  • 路径重写
三、如何引入Gateway
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
四、Gateway的工作流程

在这里插入图片描述
客户端发送请求但Gateway,Gateway Handler Mapping会根据是否符合断言来决定是否将请求交给指定路由,Gateway Web Handler按照配置给该路由的过滤器交给指定的过滤器链执行,然后执行一系列过滤器,有虚线分开是因为请求和响应都会经过过滤器链的处理,所以可以修改请求和响应。

五、Gateway的重要概念
  • 路由(Route):网关的基本构建基块。它由 ID、目的地 URI、谓词集合和过滤器集合定义。如果断言是真的,则与路由相匹配。
  • 断言(Predicate):指的是Java 8 的 Function Predicate。 输入类型是Spring框架中的ServerWebExchange。这允许您匹配来自 HTTP 请求的任何内容,例如标题或参数。
  • 过滤器(Filter):这些是通过特定工厂构建的GatewayFilter实例。在这里,您可以在发送下游请求之前或之后修改请求和响应。
六、配置路由 Predicate Factories and Gateway Filter Factories

Predicate Factories和Filter Factories分别创建断言和过滤器,我们就应该告诉他们我们应该给哪个请求和路由配置,所以应该通过配置实现,这里有两种方式:

  • 简写配置(快捷配置):
spring:
  cloud:
    gateway:
      routes:
      - id: after_route
        uri: https://example.org
        predicates:
        - Cookie=mycookie,mycookievalue

上述配置中,https://example.org这个路径的请求必须要带Cookie,且名字为mycookie=mycookievalue
否则段位为false,将不会和该路由匹配。

  • 全称配置:
spring:
  cloud:
    gateway:
      routes:
      - id: after_route
        uri: https://example.org
        predicates:
        - name: Cookie
          args:
            name: mycookie
            regexp: mycookievalue

其实就将predicates下补全了name ,args,这些可以省略,所以不常用。

可以通过yml配置,也可以通过Java Bean的方式,本质yml也是转成Java Bean嘛

  • 通过Java Bean配置:
@SpringBootApplication
public class DemogatewayApplication {
	@Bean
	public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
		return builder.routes()
			.route("after_route", r -> r.cookie("mycookie","mycookievalue")
				.uri("https://example.org"))
			.build();
	}
	}

这个和上面yml的配置一样

七、断言(predicates)的使用
1.The After Route Predicate Factory

使用格式:After= datetime ZonedDateTime(参数是要符合java的)
这个断言匹配访问的时间后于这个datetime的请求:

spring:
  cloud:
    gateway:
      routes:
      - id: after_route
        uri: https://example.org
        predicates:
        - After=2017-01-20T17:42:47.789-07:00[America/Denver]

这个路由匹配晚于2017-01-20T17:42:47.789-07:00[America/Denver]的请求

2.The Before Route Predicate Factory

使用格式:Before = datetime ZonedDateTime(参数是要符合java的)
这个断言匹配访问的时间先于这个datetime的请求

spring:
  cloud:
    gateway:
      routes:
      - id: before_route
        uri: https://example.org
        predicates:
        - Before=2017-01-20T17:42:47.789-07:00[America/Denver]

这个路由匹配先于2017-01-20T17:42:47.789-07:00[America/Denver]的请求

3.The Between Route Predicate Factory

使用格式:Between=datetime1 ,datetime2(参数是符合java)
这个断言匹配访问的时间在这个datetime之间的请求

spring:
  cloud:
    gateway:
      routes:
      - id: between_route
        uri: https://example.org
        predicates:
        - Between=2017-01-20T17:42:47.789-07:00[America/Denver], 2017-01-21T17:42:47.789-07:00[America/Denver]

这个路由匹配在2017-01-20T17:42:47.789-07:00[America/Denver]和2017-01-21T17:42:47.789-07:00[America/Denver]之间的请求

4. The Cookie Route Predicate Factory

使用格式:Cookie=name,regexp(正则表达式)
这个断言匹配访问的请求中Cookie名为name=regexpde的请求

spring:
  cloud:
    gateway:
      routes:
      - id: cookie_route
        uri: https://example.org
        predicates:
        - Cookie=chocolate, ch.p

这个路由匹配 https://example.org --cookie "chocolate=ch.p"的请求

5.The Header Route Predicate Factory

使用格式:Header=name,regexp(正则表达式)
这个断言匹配请求中带着请求头满足名字为name,且内容符合正则表示的请求

spring:
  cloud:
    gateway:
      routes:
      - id: header_route
        uri: https://example.org
        predicates:
        - Header=X-Request-Id, \d+

https://example.org --Header X-Request-Id=123可以匹配路由,因为\d+即其值为一个或多个数字

6.The Host Route Predicate Factory

使用格式:Host=patterns.Host
这个断言匹配请求头中有名为Host并且满足ant表达式的请求

spring:
  cloud:
    gateway:
      routes:
      - id: host_route
        uri: https://example.org
        predicates:
        - Host=**.somehost.org,**.anotherhost.org

https://example.org --Header host "Host=abc.somehost.org"可以匹配路由

7.The Method Route Predicate Factory

使用格式:Method=method(post,get等)
这个断言匹配请求方式是否为指定请求方式的请求。

spring:
  cloud:
    gateway:
      routes:
      - id: method_route
        uri: https://example.org
        predicates:
        - Method=GET,POST

这里Get和post的https://example.org 请求都匹配

7. The Path Route Predicate Factory

使用格式:Path=/patterns/PathMatcher
这个断言匹配请求路径中有/patterns/PathMatcher的请求

spring:
  cloud:
    gateway:
      routes:
      - id: path_route
        uri: https://example.org
        predicates:
        - Path=/red/{segment},/blue/{segment}

https://example.org/red/1 或 https://example.org/blue/1请求被匹配

8.The Query Route Predicate Factory

使用格式:Query=queryParam(正则表达式)
可以匹配请求中有名为queryParam的参数的请求

spring:
  cloud:
    gateway:
      routes:
      - id: query_route
        uri: https://example.org
        predicates:
        - Query=green

https://example.org?green=1中有请求参数green,可以匹配

9.The RemoteAddr Route Predicate Factory

使用格式:RemoteAdd=rsources
这个断言匹配发起请求的主机地址为resources的请求

spring:
  cloud:
    gateway:
      routes:
      - id: remoteaddr_route
        uri: https://example.org
        predicates:
        - RemoteAddr=192.168.1.1/24

利用192.168.1.1这台机子发起请求https://example.org可以匹配,其他主机地址不行

10.The Weight Route Predicate Factory

使用格式:Weight=group weight(权重值)
这个断言可以给不同的请求分配权重,在一定次数内,这些请求被访问的次数由权重决定

spring:
  cloud:
    gateway:
      routes:
      - id: weight_high
        uri: https://weighthigh.org
        predicates:
        - Weight=group1, 8
      - id: weight_low
        uri: https://weightlow.org
        predicates:
        - Weight=group1, 2

上述配置80%的请求会匹配到https://weighthigh.org,20%会匹配到https://weightlow.org

八、GatewayFilter Factories

路由过滤器允许以某种方式修改传入的 HTTP 请求或传出的 HTTP 响应。但是只能对指定的路由起作用。Spring Could内置了很多路由过滤器,这些过滤器都GatewayFilter Factories产生。

1.The AddRequestHeader GatewayFilter Factory

为请求头中添加信息的路由过滤器

spring:
  cloud:
    gateway:
      routes:
      - id: add_request_header_route
        uri: https://example.org
        filters:
        - AddRequestHeader=X-Request-red, blue

以上的配置将为请求的请求头中添加X-Request-red=blue属性
用curl测试,发送请求:

https://example.org

经过滤器处理后请求:

https://example.org --Header "X-Request-red=blue"
2. The AddRequestParameter GatewayFilter Factory

为请求中添加请求参数

spring:
  cloud:
    gateway:
      routes:
      - id: add_request_parameter_route
        uri: https://example.org
        filters:
        - AddRequestParameter=red, blue

以上配置为请求中添加red=blue的参数
原本请求:

https://example.org

经过滤器处理后请求:

https://example.org?red=blue
3.The PrefixPath GatewayFilter Factory

为请求中添加路径的前缀

spring:
  cloud:
    gateway:
      routes:
      - id: prefixpath_route
        uri: https://example.org
        filters:
        - PrefixPath=/mypath

以上配置为请求中添加/mypath的前缀
原本请求:

https://example.org

经过滤器处理后请求:

https://example.org/mypath
4.The StripPrefix GatewayFilter Factory

剔除请求中的指定位数的前缀

spring:
  cloud:
    gateway:
      routes:
      - id: nameRoot
        uri: https://nameservice
        predicates:
        - Path=/name/**
        filters:
        - StripPrefix=2

以上配置将会剔除前面两位的前缀
原本请求:

https://example.org/name/abc

经过滤器处理后请求:

https://example.org
5.The SetStatus GatewayFilter Factory

设置响应的状态码

spring:
  cloud:
    gateway:
      routes:
      - id: setstatusstring_route
        uri: https://example.org
        filters:
        - SetStatus=BAD_REQUEST
      - id: setstatusint_route
        uri: https://example.org
        filters:
        - SetStatus=401

以上配置将该请求的响应状态码改为401

6.Spring Cloud CircuitBreaker GatewayFilter Factory

这个过滤器支持和熔断器一起使用,提供熔断和fallback功能。SpringCould的支持多种熔断器,要是使用,将其依赖引入即可,这里我们是Hystrix来作为熔断器结合该过滤器使用,所以引入其依赖:

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

路由过滤器配置:

spring:
  cloud:
    gateway:
      routes:
      - id: circuitbreaker_route
        uri: lb://backing-service:8088
        predicates:
        - Path=/consumingServiceEndpoint
        filters:
        - name: CircuitBreaker
          args:
            name: myCircuitBreaker
            fallbackUri: forward:/fallback

fallbackUri: forward:/fallback指发生了异常等,用/fallback对应的controller这个方法兜底,配置这个controller:

@RestController
public class FallbackController {

    @GetMapping("/fallback")
    public Object fallback() {
        Map<String,Object> result = new HashMap<>();
        result.put("data",null);
        result.put("message","Get request fallback!");
        result.put("code",500);
        return result;
    }
}

当然也可之间利用该过滤器修改返回状态码和信息,而不用在fallback中配置:

spring:
  cloud:
    gateway:
      routes:
      - id: circuitbreaker_route
        uri: lb://backing-service:8088
        predicates:
        - Path=/consumingServiceEndpoint
        filters:
        - name: CircuitBreaker
          args:
            name: myCircuitBreaker
            fallbackUri: forward:/fallback
			statusCodes:
              - 500
              - "NOT_FOUND"
7.The RequestRateLimiter GatewayFilter Factory

路由过滤器也可以进行流量控制,当请求频繁访问,可以对其进行控制,提高可用性,如果请求太大默认会返回HTTP 429-太多请求状态。

我们可以针对不同的情况自定义我们的限流策略,通过实现KeyResolver接口
KeyResolver.java

public interface KeyResolver {
    Mono<String> resolve(ServerWebExchange exchange);
}

自定义我们的限流策略:

@Configuration
public class RedisRateLimiterConfig {
//根据请求参数中的username进行限流,当相同的username访问达到限流阈值,限流
    @Bean
    KeyResolver userKeyResolver() {
        return exchange -> Mono.just(exchange.getRequest().getQueryParams().getFirst("username"));
    }

//根据访问IP进行限流
    @Bean
    public KeyResolver ipKeyResolver() {
        return exchange -> Mono.just(exchange.getRequest().getRemoteAddress().getHostName());
    }
}
要达到限流,我们还要结合redis实现,当然这里redis的配置就不详述了。这里运用的算法是Token Bucket Algorithm。
接下来就是像上面配置过滤一样:

```yaml
spring:
  cloud:
    gateway:
      routes:
      - id: requestratelimiter_route
        uri: https://example.org
        filters:
        - name: RequestRateLimiter
          args:
            redis-rate-limiter.replenishRate: 10
            redis-rate-limiter.burstCapacity: 20
            redis-rate-limiter.requestedTokens: 1
            key-resolver: "#{@userKeyResolver}"

这里有几个参数:

  • redis-rate-limiter.replenishRate:允许用户每秒进行多少请求
  • redis-rate-limiter.burstCapacity:允许用户在一秒内进行的最大请求数,将此值设置为零阻止所有请求
  • redis-rate-limiter.requestedTokens:这是每个请求从存储桶中取出的token数量,并默认为1
  • key-resolver: “#{@userKeyResolver}”:主义这里可以使用EL表达式将我们自定义的限流策略配置进来。

还有其他很多路由过滤器,详情可以参考官网:Spring Could Gateway文档
注意:这些过滤器都是针对某一个具体的路由,当然我们也可以针对全局的配置

九、全局的过滤器

配置全局过滤器:

@Configuration
public class CustomGlobalFilter implements GlobalFilter, Ordered {

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        log.info("custom global filter");
        return chain.filter(exchange);
    }

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

只要实现接口GlobalFilter和Ordered,在filter方法中我们可以些代码,如实现全局的鉴权等功能,而getOder方法是规定该过滤执行的顺序,数字越小优先级越高

十、结合服务注册与发现中心Eureka实现动态路由

我们知道,在微服务中一个服务是不可能只有一个实例的,所以我们在访问这些服务的时候也不可能讲过他们的路由写死,比如直接写某个服务的ip+端口号访问,这样既麻烦,而且也不好做负载均衡,我们要写成动态的,就要写入一个服务的服务名,然后通过服务名动态的访问这个服务名下的多个实例,那么我们怎么通过服务名就得到对应的路由,这就是Eureka的作用,所以就要引入服务注册与发现中心Eureka

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>

然后进行配置:

pring:
  application:
    name: cloud-gateway
  cloud:
    gateway:
      discovery:
        locator:
          enabled: true   #开启从注册中心动态创建路由的功能,利用微服务名进行路由
      routes:
        - id: payment_routh #payment_routh    #路由的ID,没有固定规则但要求唯一,简易配合服务名
          #uri: http://localhost:8001         #匹配后提供服务的路由地址
          uri: lb://cloud-provider-service   #匹配后提供服务的路由地址,lb后跟提供服务的微服务的名,不要写错
          predicates:
            - Path=/payment/get/**          #断言,路径相匹配的进行路由

        - id: payment_routh2 #payment_routh   #路由的ID,没有固定规则但要求唯一,简易配合服务名
          #uri: http://localhost:8001          #匹配后提供服务的路由地址
          uri: lb://cloud-provider-service     #匹配后提供服务的路由地址,lb后跟提供服务的微服务的名,不要写错
          predicates:
            - Path=/payment/lb/**             #断言,路径相匹配的进行路由

重点注意gateway.discovery.locator.enabled=true,让gateway能够发现服务,获得其访问的路由等信息,然后注意 uri: lb://cloud-provider-service 我们写的是微服务的名字,而不是具体的IP和端口了,另外,加了lb:这个是实现一个负载均衡的效果

十一、总结

Spring Could Gateway是一个提供网关服务的技术,同样也有网关作用的还有zuul以及zuul2,但是毫无疑问,Gateway是常用的,因为它也是Spring家族的一员。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值