网关的作用
在微服务架构下,单体应用被分割成多个微服务,如果将所有的微服务直接对外暴露,会出现一些安全问题,全部做鉴权处理的话,不光效率底下,而且管理起来更是复杂,而且有一些服务协议不是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'
编写配置文件, 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路由断言工程接收两个参数:group和
weight。通过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过滤器
用于重定向操作,工厂有两个参数,status
和url
。该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方法exceptions
:IOException
和TimeoutException
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
待补充