在云架构中运行着众多客户端和服务端,API网关的存在提供了保护和路由消息,隐藏服务,限制负载等等功能。下图是spring cloud gateway所处的位置。
它有三大概念:
路由:路由是构建网关的基本模块,它由ID,目标URI,一系列的断言Predicates和过滤器Filters组成,如果断言为true,则匹配该路由。
断言:参考Java8的java.util.function.Predicate,开发人员可以匹配HTTP请求中的所有内容,例如请求头或请求参数,如果请求与断言相匹配则进行路由。
过滤:Spring框架中GatewayFilter的实例,使用过滤器,可以载请求被路由前或者后对请求进行修改。
工作流程图如下:
SpringCloud Gateway 和nginx 都在流量进入服务前做一些处理, 那谁先执行呢,他们之间有联系吗 ?
在微服务架构中,SpringCloud Gateway和Nginx的执行顺序和它们之间的联系主要取决于你的具体配置和架构设计。
-
执行顺序:
- 如果你将Nginx用作反向代理服务器,并且将所有入站流量都首先路由到Nginx,那么Nginx将首先执行。Nginx可以根据其配置将请求转发到后端的SpringCloud Gateway或其他微服务。
- 如果SpringCloud Gateway是直接暴露给外部用户的,那么它将首先执行。但是,你仍然可以在SpringCloud Gateway之前使用Nginx作为反向代理,以增加额外的安全性、负载均衡或其他功能。
-
联系:
- 反向代理:Nginx经常被用作反向代理服务器,将外部请求转发到后端的SpringCloud Gateway或其他微服务。这可以为你的架构提供额外的安全性、负载均衡和缓存功能。
- 负载均衡:Nginx和SpringCloud Gateway都支持负载均衡功能。Nginx可以在其配置中定义负载均衡规则,将请求分发到多个SpringCloud Gateway实例或其他微服务实例上。同样,SpringCloud Gateway也可以配置负载均衡策略,将请求路由到后端的微服务实例。
- 安全性:Nginx和SpringCloud Gateway都可以提供安全性功能,如SSL终止、IP白名单、基本身份验证等。但是,它们的安全性功能可能有所不同,具体取决于你的配置和需求。
- 解耦和细分:在某些情况下,Nginx可能不再承担服务的路由分发和负载均衡的角色,而是将这些功能转交给更专业的工具(如SpringCloud Gateway)来处理。这是一种解耦和细分的表现,可以使你的架构更加灵活和可扩展。
Nginx和SpringCloud Gateway之间可以存在紧密的联系,但也可以完全独立地运行。需要根据你的具体需求和架构设计来决定如何配置和使用它们。
那SpringCloud Gateway 和spring security谁先执行呢?
在Spring Cloud微服务架构中,SpringCloud Gateway
和Spring Security
的执行顺序取决于它们是如何配置和集成的。但通常来说,SpringCloud Gateway
作为API网关,会首先接收到来自客户端的请求,并在处理这些请求时可能会涉及到Spring Security
的安全检查。
以下是它们之间可能的工作流程:
- 客户端发起请求:客户端(如Web浏览器、移动应用或其他服务)向API网关(即SpringCloud Gateway)发起HTTP请求。
- SpringCloud Gateway接收请求:SpringCloud Gateway作为API网关,会首先接收到这些请求。它会根据配置的路由规则来确定将请求转发到哪个微服务。
- SpringCloud Gateway的安全检查(如果配置):在转发请求之前,SpringCloud Gateway可能会执行一些安全检查。这些检查可能包括验证请求头、请求参数或JWT令牌等。这些安全检查可以通过自定义的过滤器(Filter)来实现,这些过滤器可以在请求被转发到微服务之前对请求进行拦截和处理。
- 转发请求到微服务:如果请求通过了SpringCloud Gateway的安全检查(如果有的话),那么它就会被转发到相应的微服务。
- Spring Security在微服务中的执行:当请求到达微服务时,如果微服务配置了Spring Security,那么Spring Security就会执行相应的安全检查。这些检查可能包括验证用户的身份(如用户名和密码登录、OAuth令牌等)、检查用户是否有权访问请求的资源等。
- 微服务处理请求并返回响应:如果请求通过了Spring Security的安全检查,那么微服务就会处理该请求并返回响应。这个响应会经过SpringCloud Gateway返回给客户端。
SpringCloud Gateway和Spring Security的安全检查是独立的,它们可以分别配置和执行。在某些情况下,你可能需要在SpringCloud Gateway中执行一些安全检查(如验证JWT令牌),然后在微服务中执行更细粒度的安全检查(如基于角色的访问控制)。这取决于具体需求和架构设计。
spring cloud gateway 断言配置:
predicates:
- Before=2017-01-20T17:42:47.789-07:00[America/Denver] # 在..之前可以匹配
- After=2017-01-20T17:42:47.789-07:00[America/Denver] # 在..之后可以匹配
- Between=xxx,xxx # 在..之间可以匹配
- Cookie=chocolate, ch.p # 带cookie
- Header=X-Request-Id, \d+ # 规定header
- Host=**.somehost.org,**.anotherhost.org # 规定host
- Method=GET,POST # 规定请求方法
- Path=/red/{segment},/blue/{segment} # 规定请求路径
- Query=green # 规定请求参数
- RemoteAddr=192.168.1.1/24 # 规定remoteAddr
# 将80%的流量转到weighthigh.org,20%转到weightlow.org
- id: weight_high
uri: https://weighthigh.org
predicates:
- Weight=group1, 8
- id: weight_low
uri: https://weightlow.org
predicates:
- Weight=group1, 2
例子:假如有两个相同的服务实例cloud-payment-service(即它们提供相同的功能和API),并且你希望它们能够共同分担负载(即实现负载均衡,端口分别为8001和8002),现在通过gateway的断言设置分别请求这两个服务里的/payment/hello方法。
gateway的yml配置:
server:
port: 9527
spring:
application:
name: cloud-gateway
cloud:
gateway:
discovery:
locator:
enabled: true #开启从注册中心动态创建路由的功能,利用微服务名进行路由
routes:
- id: payment_routh #payment_route #路由的ID,没有固定规则但要求唯一,建议配合服务名
#uri: http://localhost:8001 #匹配后提供服务的路由地址
uri: lb://cloud-payment-service #匹配后提供服务的路由地址
predicates:
- Path=/payment1/** # 断言,路径相匹配的进行路由
- After=2020-11-26T21:27:26.256+08:00[Asia/Shanghai]
- id: payment_routh2 #payment_route #路由的ID,没有固定规则但要求唯一,建议配合服务名
#uri: http://localhost:8001 #匹配后提供服务的路由地址
uri: lb://cloud-payment-service #匹配后提供服务的路由地址
predicates:
- Path=/payment2/lb/** # 断言,路径相匹配的进行路由
- After=2020-11-25T22:42:23.608+08:00[Asia/Shanghai]
- Cookie=username,hyh
#- Header=X-Request-Id, \d+ # 请求头要有X-Request-Id属性并且值为整数的正则表达式
# - Host=**.somehost.org,**.anotherhost.org # 匹配hostname
# - Method=GET,POST
# - Path=/red/{segment},/blue/{segment}
# - Query=green
# - RemoteAddr=192.168.1.1/24
# - Weight=group1, 2
- id: payment_routh3 #payment_route #路由的ID,没有固定规则但要求唯一,建议配合服务名
#uri: http://localhost:8001 #匹配后提供服务的路由地址
uri: lb://cloud-payment-service #匹配后提供服务的路由地址
predicates:
- Path=/payment/hello # 断言,路径相匹配的进行路由
- After=2020-11-25T22:42:23.608+08:00[Asia/Shanghai]
- Cookie=username,hyh
- Header=X-Request-Num, \d+
eureka:
instance:
hostname: cloud-gateway-service
instance-id: gateway9527
prefer-ip-address: true
client: #服务提供者provider注册进eureka服务列表内
service-url:
register-with-eureka: true
fetch-registry: true
defaultZone: http://eureka7001.com:7001/eureka
8001的服务的方法:
@GetMapping("/payment/hello")
public String helloNum() {
log.info("(8001)/payment/hello 执行了");
return serverPort + "/payment/hello 执行了";
}
8002的服务的方法:
@GetMapping("/payment/hello")
public String helloNum() {
log.info("(8001)/payment/hello 执行了");
return serverPort + "/payment/hello 执行了";
}
设置请求参数:
连点两次发送请求gateway服务,发现两次分别调用了两个服务的同一个方法:
如果将请求头header或者cookies设置为错误的值,不满足断言,gateway则不转发这个请求: