Spring Cloud: API网关 Gateway

网关的作用

在微服务架构下,单体应用被分割成多个微服务,如果将所有的微服务直接对外暴露,会出现一些安全问题,全部做鉴权处理的话,不光效率底下,而且管理起来更是复杂,而且有一些服务协议不是Web友好的协议。

为了解决上述问题,出现了使用API网管的解决方案。API网关自身也是一个服务,并且是后端服务的唯一入口。从面向对象设计的角度看,它与外观模式类似。API网关封装了系统内部架构,为每个客户端提供一个定制的API。除此之外,它还可以负责身份验证、监控、负载均衡、限流、降级与应用检测等功能。

Spring Cloud Gateway 简介

Spring Cloud Gateway是Spring官方基于Spring 5.0、Spring Boot 2.0和ProjectReactor等技术开发的网关,Spring Cloud Gateway旨在为微服务架构提供简单、有效且统一的API路由管理方式。Spring Cloud Gateway作为Spring Cloud生态系中的网关

Spring Cloud Gateway依赖Spring Boot和Spring WebFlux,基于Netty运行。它不能在传统的servlet容器中工作,也不能构建成war包。

Gateway中最重要的几个概念:

  • 路由(route):路由是网关最基础的部分,路由信息由一个ID、一个目的url、一组断言工厂和一组Filter组成。如果路由断言为真,则说明请求的url和配置的路由匹配。
  • 断言(Predicate)。Java 8中的断言函数。Spring Cloud Gateway中的断言函数输入类型是Spring 5.0框架中的ServerWebExchange。Spring CloudGateway中的断言函数允许开发者去定义匹配来自于Http Request中的任何信息,比如请求头和参数等。
  • 过滤器(filter)。一个标准的Spring webFilter。Spring Cloud Gateway中的Filter分为两种类型的Filter,分别是Gateway Filter和Global Filter。过滤器Filter将会对请求和响应进行修改处理。

基础应用

创建一个新的consul-gateway用作API网关,和之前的consul-consumer作为服务,服务注册到了Consul上,通过请求网管获取服务

Consul的使用和consul-consumer的创建可以看之前文章:Spring Cloud: 注册中心Consul使用
在这里插入图片描述

1. 新建一个项目consul-gateway

依赖如下, 添加consul-config作为配置中心:

    implementation 'org.springframework.boot:spring-boot-starter-actuator'
    implementation 'org.springframework.cloud:spring-cloud-starter-gateway:2.2.2.RELEASE'
    implementation 'org.springframework.cloud:spring-cloud-starter-consul-discovery:2.2.2.RELEASE'
    implementation 'org.springframework.cloud:spring-cloud-starter-consul-config:2.2.2.RELEASE'

pswebgateway使WebFlux\color{red}{ps:注意不要添加web依赖,因为gateway使用的是WebFlux}

编写配置文件, bootstrap.yml:

spring:
  application:
    name: consul-gateway
  cloud:
    consul:
      host: localhost
      port: 8500
      discovery:
        prefer-ip-address: true
        service-name: ${spring.application.name}
      config:
        format: yaml    # 配置各式yaml或properties
        profile-separator: ':'   # 配置分隔符,默认为“,”

management:
  endpoints:
    web:
      exposure:
        include: "*"
  endpoint:
    health:
      show-details: always
       

启动类不需要修改。

在这里插入图片描述

成功添加到注册中心。

Gateway的各种网管功能配置用起来很舒服,故意避开了代码编写,可以直接通过配置文件进行编写,这样的话只要维护修改配置文件就可以更改网管的路由筛选逻辑,配置文件再通过配置中心统一管理,逻辑更加方便维护管理。

2. 配置文件

application. yml:

server:
  port: 8730

spring:
  cloud:
    gateway:
      routes:
      - id: path_route
        uri: http://localhost:8710
        predicates:
          - Path=/feign

      - id: path_route
        uri: https://blog.csdn.net
        predicates:
          - Path=/tonydz0523/**

这里直接在配置文件中编写路由逻辑:

  - id: path_route
    uri: http://localhost:8710
    predicates:
      - Path=/feign
  • http://localhost:8710是consumer的地址
  • - Path=/feign是可以跳转的路径
  • 当你访问 http://localhost:8730/feign就会跳转到http://localhost:8710/feign

在这里插入图片描述

如果需要支持多级Path的话只要加上**即可:

      - id: path_route
        uri: https://blog.csdn.net
        predicates:
          - Path=/tonydz0523/**

访问http://localhost:8730/tonydz0523/article/details/106551483就会跳转到http://blog.csdn.net/tonydz0523/article/details/106551483

在这里插入图片描述

3. 获取Consul注册服务

首先要先开启locator功能:

spring:
  cloud:
    gateway:
      discovery:
        locator:
          enabled: true

然后添加route规则:

      - id: consul-consumer
        uri: lb://consul-consumer
        predicates:
          - Path=/consul-consumer/**

uri以lb://开头(lb代表从注册中心获取服务),后面接的就是你需要转发到的服务名称,这个服务名称必须跟Consul中的对应,否则会找不到服务

通过访问http://localhost:8730/consul-consumer/feign即可通过consul注册中心跳转到consul-consumer服务:

在这里插入图片描述

由于我注册在Consul上的两个consul-consumer其中又一个没有写feign路径的服务,因此一个访问没有结果。

Gateway路由断言工厂

After路由断言

在设置的After时间之后可以进行转发,否者不可以

      - id: after_route
        uri: https://example.org
        predicates:
        - After=2020-06-06T16:32:12.975035+08:00[Asia/Shanghai]

时间可以ZonedDateTime通过获得:

ZonedDateTime.now().format(DateTimeFormatter.ISO_ZONED_DATE_TIME);

Before路由断言

在设置的Before时间之后可以进行转发,否者不可以

      - id: before_route
        uri: https://example.org
        predicates:
        - Before=2020-06-06T16:32:12.975035+08:00[Asia/Shanghai]

Between路由断言

设置一个时间段,访问时间在这个时间段的话可以跳转,两个时间通过隔开

      - id: between_route
        uri: https://example.org
        predicates:
        - Between=2020-06-06T16:32:12.975035+08:00[Asia/Shanghai],2020-06-07T16:32:12.975035+08:00[Asia/Shanghai]

Cookie路由断言

cookie名称对应的key和value。当请求中携带的cookie和Cookied断言工厂中配置的cookie一致,则路由匹配成功,否则匹配不成功;key和value通过隔开,value位置可以是正则表达式用来匹配value

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

Header路由断言

Header路由断言工厂用于根据配置的路由header信息进行断言匹配路由,匹配成功进行转发,否则不进行转发。key和value通过通过隔开,value位置可以是正则表达式用来匹配value

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

Host路由断言

Host路由断言工厂根据配置的Host,对请求中的Host进行断言处理,断言成功则进行路由转发,否则不转发。可以使用**模糊匹配,而且添加多个通过隔开

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

Method路由断言

Method路由断言工厂会根据路由信息配置的method对请求方法是Get或者Post等进行断言匹配

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

只有GET和POST请求可以转发

Path路由断言

Path路由断言工厂接收一个参数,根据Path定义好的规则来判断访问的URI是否匹配

      - id: path_route
        uri: https://example.org
        predicates:
        - Path=/red/{segment},/blue/{segment},/yellow/**

如果请求路径为/red/xxx可以通过匹配,也可以使用正则进行匹配,如/yellow/**

Query路由断言

Query路由断言工厂会从请求中获取两个参数,将请求中参数和Query断言路由中的配置进行匹配,一致则转发成功,否则转发失败

      - id: query_route
        uri: https://example.org
        predicates:
        - Query=green, re.

两个参数一个必需的参数和一个可选的正则表达式, https://example.org?green=rex可以匹配

RemoteAddr路由断言

RemoteAddr路由断言工厂配置一个IPv4或IPv6网段的字符串或者IP。当请求IP地址在网段之内或者和配置的IP相同,则表示匹配成功,成功转发,否则不能转发。例如192.1680.1/16是一个网段,其中192.168.0.1是IP地址,16是子网掩码,当然也可以直接配置一个IP。

      - id: remoteaddr_route
        uri: https://example.org
        predicates:
        - RemoteAddr=192.168.1.1

Weight路由断言

Weight路由断言工程接收两个参数:groupweight。通过group将多个uri分为一组,weight则是权重值

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

route会将约80%的流量转发至weighthigh.org,并将约20%的流量转发至weightlow.org。

Gateway内置的Filter

Spring Cloud Gatewat中内置很多的路由过滤工厂,当然可以自己根据实际应用场景需要定制的自己的路由过滤器工厂。路由过滤器允许以某种方式修改请求进来的http请求或返回的http响应。路由过滤器主要作用于需要处理的特定路由。SpringCloud Gateway提供了很多种类的过滤器工厂,过滤器的实现30多个。总得来说,可以分为七类:Header、Parameter、Path、Status、Redirect跳转、Hytrix熔断和RateLimiter

介绍几种常用的:

AddRequestHeader过滤器

通过名称我们可以快速明白这个过滤器工厂的作用是添加请求头。

      - id: add_request_header_route
        uri: https://example.org
        filters:
        - AddRequestHeader=X-Request-red, blue
        
      - id: add_request_header_route
        uri: https://example.org
        predicates:
        - Path=/red/{segment}
        filters:
        - AddRequestHeader=X-Request-Red, Blue-{segment}

符合规则匹配成功的请求,将添加X-Request-red:blue请求头,将其传递到后端服务中,后方服务可以直接获取请求头信息。URI变量中的值,可以应用到header中

AddRequestParameter过滤器

AddRequestParameter过滤器作用是对匹配上的请求路由添加请求参数,添加的是一对key和value

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

添加访问参数red=blue

RemoveRequestHeader过滤器

RemoveRequestHeader是移除请求头的过滤器工厂,可以在请求转发到后端服务之前进行Header的移除操作。与上面相反是将减少请求头

      - id: removerequestheader_route
        uri: https://example.org
        filters:
        - RemoveRequestHeader=X-Request-Foo

SetStatus过滤器

SetStatus过滤器工厂接收单个状态,用于设置Http请求的响应码。它必须是有效的Spring Httpstatus(org.springframework.http.HttpStatus)。它可以是整数值404或枚举类型NOT_FOUND。

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

可以通过如下设置以从代理请求返回原始HTTP状态代码:

spring:
  cloud:
    gateway:
      set-status:
        original-status-header-name: original-http-status

RewritePath过滤器

这使用Java正则表达式提供了一种灵活的方式来重写请求路径,两个参数,前面用来匹配原来路径,后面是新生成路径

      - id: rewritepath_route
        uri: https://example.org
        predicates:
        - Path=/red/**
        filters:
        - RewritePath=/red(?<segment>/?.*), $\{segment}

StripPrefix过滤器

StripPrefixGatewayFilterFactory是一个对针对请求url前缀进行处理的filter工厂,用于去除前缀。而PrefixPathGatewayFilterFactory是用于增加前缀。

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

用于减少前缀,如https://blog.csdn.net/tonydz0523/article/details/106551483减少两个前缀->https://blog.csdn.net/details/106551483

RedirectTo过滤器

用于重定向操作,工厂有两个参数,statusurl。该status参数应该是300系列重定向HTTP代码,例如301。该url参数应该是有效的URL。

      - id: prefixpath_route
        uri: https://example.org
        filters:
        - RedirectTo=302, https://acme.org

Retry过滤器

网关作为所有请求流量的入口,网关对路由进行协议适配和协议转发处理的过程中,如果出现异常或网络抖动,为了保证后端服务请求的高可用,一般处理方式会对网络请求进行重试,Retry过滤器包含如下参数:

  • retries:应尝试的重试次数。
  • statuses:应重试的HTTP状态代码,以表示org.springframework.http.HttpStatus
  • methods:应该重试的HTTP方法,以表示org.springframework.http.HttpMethod
  • series:可以retry的状态,使用表示org.springframework.http.HttpStatus.Series
  • exceptions:可以激活retry的异常列表。
  • backoff:为重试配置的指数补偿。重试在的间隔后执行firstBackoff * (factor ^ n),其中n为迭代。如果maxBackoff已配置,则应用的最大退避限制为maxBackoff。如果basedOnPreviousValue为true,则使用prevBackoff * factor计算间隔。

默认配置如下:

  • retries:3次
  • series:5XX系列
  • methods:GET方法
  • exceptionsIOExceptionTimeoutException
  • backoff:禁用
      - id: retry_test
        uri: http://localhost:8080/flakey
        predicates:
        - Host=*.retry.com
        filters:
        - name: Retry
          args:
            retries: 3
            statuses: BAD_GATEWAY
            methods: GET,POST
            backoff:
              firstBackoff: 10ms
              maxBackoff: 50ms
              factor: 2
              basedOnPreviousValue: false

Hystrix过滤器

Hystrix的相关内容,请看之前文章:SpringCloud: 熔断器Hystrix 、Turbine (多图)

需要一个name参数,它是的名称HystrixCommand

      - id: hystrix_route
        uri: https://example.org
        filters:
        - Hystrix=myCommandName

Hystrix过滤器还可以接受可选fallbackUri参数

      - id: hystrix_route
        uri: lb://backing-service:8088
        predicates:
        - Path=/consumingserviceendpoint
        filters:
        - name: Hystrix
          args:
            name: fallbackcmd
            fallbackUri: forward:/incaseoffailureusethis
        - RewritePath=/consumingserviceendpoint, /backingserviceendpoint

默认过滤器

要添加过滤器并将其应用于所有路由,可以使用spring.cloud.gateway.default-filters。此属性采用过滤器列表

spring:
  cloud:
    gateway:
      default-filters:
      - AddResponseHeader=X-Response-Default-Red, Default-Blue
      - PrefixPath=/httpbin

Cors配置

您可以配置网关以控制CORS行为。“全局” CORS配置是URL模式到CorsConfiguration的映射。以下示例配置了CORS:

spring:
  cloud:
    gateway:
      globalcors:
        cors-configurations:
          '[/**]':
            allowedOrigins: "https://docs.spring.io"
            allowedMethods:
            - GET

RequestRateLimiter

待补充

GlobalFilter

待补充

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章