为了保障文章的流畅性(文章穿插大量的环境搭建没意思,会干扰文章的主题,无聊的很),将环境的搭建与测试,工具的版本说明放了文末: 五、环境搭建。
一、概述
https://spring.io/projects/spring-cloud-gateway
该项目提供了在 Spring WebFlux 或 Spring WebMVC 之上构建 API 网关的库。Spring Cloud Gateway 旨在提供一种简单而有效的方法来路由到 API 并为它们提供跨切关注点,例如:安全性、监控
Cloud全家桶中有个很重要的组件就是网关,在1.x版本中都是采用的Zuul网关;
但在2.x版本中,zuul的升级一直跳票,SpringCloud最后自己研发了一个网关SpringCloud Gateway替代Zuul,
那就是SpringCloud Gateway一句话:gateway是原zuul1.x版的替代
作用:
- 反向代理
- 鉴权
- 流量控制
- 熔断
- 日志监控
总结:
Spring Cloud Gateway组件的核心是一系列的过滤器,通过这些过滤器可以将客户端发送的请求转发(路由)到对应的微服务。 Spring Cloud Gateway是加在整个微服务最前沿的防火墙和代理器,隐藏微服务结点IP端口信息,从而加强安全保护。Spring Cloud Gateway本身也是一个微服务,需要注册进服务注册中心。
1.1、三大核心
https://cloud.spring.io/spring-cloud-gateway/reference/html/#glossary
- Route(路由):路由是构建网关的基本模块,它由ID,目标URI,一系列的断言和过滤器组成,如果断言为true则匹配该路由
- Predicate(断言):参考的是Java8的java.util.function.Predicate开发人员可以匹配HTTP请求中的所有内容(例如请求头或请求参数),如果请求与断言相匹配则进行路由
- Filter(过滤):指的是Spring框架中GatewayFilter的实例,使用过滤器,可以在请求被路由前或者之后对请求进行修改。
总结:web前端请求,通过一些匹配条件,定位到真正的服务节点。并在这个转发过程的前后,进行一些精细化控制。predicate就是我们的匹配条件;filter,就可以理解为一个无所不能的拦截器。有了这两个元素,再加上目标uri,就可以实现一个具体的路由了
1.2、工作流程
https://cloud.spring.io/spring-cloud-gateway/reference/html/#gateway-how-it-works
下图提供了 Spring Cloud Gateway 工作原理的高级概述:
客户端向 Spring Cloud Gateway 发出请求。如果 Gateway Handler Mapping 确定请求与路由匹配,则将其发送到 Gateway Web Handler。此处理程序通过特定于请求的过滤器链运行请求。过滤器被虚线分开的原因是过滤器可以在发送代理请求之前和之后运行逻辑。所有“前”过滤器逻辑都会执行。然后发出代理请求。发出代理请求后,将运行“后”过滤器逻辑。
在没有端口的路由中定义的 URI 分别获得 HTTP 和 HTTPS URI 的默认端口值 80 和 443。
核心逻辑:路由转发+断言判断+执行过滤器链
二、实战:基本使用
2.1、改POM
<!--gateway-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
2.2、写YML
server:
port: 8763
spring:
application:
#对应consu控制台的实例名称
name: gateway
cloud:
consul:
host: 192.168.200.129
port: 8500
discovery:
#节点检查的时候默认使用hostname报错,建议true通过ip访问
prefer-ip-address: true
#对应consu控制台的servcie名称(restTemplate调用)
serviceName: gateway
2.3、主启动
package com.gateway;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
/**
* @Author: 史小创
* @Time: 2024/8/25 下午6:52
* @Description:
*/
@SpringBootApplication
@EnableDiscoveryClient
public class GatewayApplication {
public static void main(String[] args) {
org.springframework.boot.SpringApplication.run(GatewayApplication.class, args);
}
}
http://192.168.200.129:8500/ui/dc1/services
三、网关如何做路由映射
诉求:我们不想暴漏服务的提供者的端口,想在外部包一层网关
3.1、正常访问
http://localhost:8886/provider/gateway/getnumber/8886
http://localhost:8886/provider/gateway/getname/shixiaochuang
3.2、配置网关
gateway:
routes:
- id: provider_routh1 #路由的ID(类似mysql主键ID),没有固定规则但要求唯一,建议配合服务名
uri: http://localhost:8886 #匹配后提供服务的路由地址
predicates:
- Path=/provider/gateway/getnumber/** # 断言,路径相匹配的进行路由
- id: provider_routh2 #pay_routh2 #路由的ID(类似mysql主键ID),没有固定规则但要求唯一,建议配合服务名
uri: http://localhost:8886 #匹配后提供服务的路由地址
predicates:
- Path=/provider/gateway/getname/** # 断言,路径相匹配的进行路由
http://localhost:8888/provider/gateway/getnumber/8888
http://localhost:8888/provider/gateway/getname/shixiaochuang
3.3、启动的服务的消费者,网关是否起作用呢
http://localhost:8889/consumer/gateway/getnumber/8889
http://localhost:8889/consumer/gateway/getname/shixiaochuang
http://localhost:8889/consumer/gateway/getnumber/8889
http://localhost:8889/consumer/gateway/getname/shixiaochuang
网关貌似没有任何作用,怎么办呢??
3.4、配置接口
@FeignClient(value = "gateway")
重启测试:
http://localhost:8889/consumer/gateway/getname/shixiaochuang
http://localhost:8889/consumer/gateway/getnumber/8889
那么停止掉网关呢??
http://localhost:8889/consumer/gateway/getname/shixiaochuang
http://localhost:8889/consumer/gateway/getnumber/8889
3.5、问题
四、实战:进阶使用
4.1、Route以微服务名-动态获取服务URI
https://cloud.spring.io/spring-cloud-gateway/reference/html/#reactive-loadbalancer-client-filter
gateway:
routes:
- id: provider_routh1 #路由的ID(类似mysql主键ID),没有固定规则但要求唯一,建议配合服务名
#uri: http://localhost:8886 #匹配后提供服务的路由地址
uri: lb://gateway-provider #匹配后提供服务的路由地址
predicates:
- Path=/provider/gateway/getnumber/** # 断言,路径相匹配的进行路由
- id: provider_routh2 #pay_routh2 #路由的ID(类似mysql主键ID),没有固定规则但要求唯一,建议配合服务名
#uri: http://localhost:8886 #匹配后提供服务的路由地址
uri: lb://gateway-provider #匹配后提供服务的路由地址
predicates:
- Path=/provider/gateway/getname/**
http://localhost:8889/consumer/gateway/getnumber/8889
http://localhost:8889/consumer/gateway/getname/shixiaochuang
4.2、Predicate断言(谓词)
4.2.1、概述
https://cloud.spring.io/spring-cloud-gateway/reference/html/#gateway-request-predicates-factories
Spring Cloud Gateway 作为 Spring WebFlux HandlerMapping 基础架构的一部分匹配路由。Spring Cloud Gateway 包含许多内置路由谓词工厂。所有这些谓词都匹配 HTTP 请求的不同属性。您可以使用逻辑 and 语句组合多个路由谓词工厂。
我们在配置文件中写的断言规则只是字符串,这些字符串会被Predicate Factory读取并处理,转变为路由判断的条件
例如Path=/user/**是按照路径匹配,这个规则是由
org.springframework.cloud.gateway.handler.predicate.PathRoutePredicateFactory
类来
处理的,像这样的断言工厂在SpringCloudGateway还有十几个:
名称 | 说明 | 示例 |
---|---|---|
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 | 权重处理 |
我们只需要掌握Path这种路由工程就可以了。
4.2.2、常用的内置Route Predicate
Spring Cloud Gateway的12个断言工厂用于基于时间、请求属性(如Cookie、Header、Host、Method、Path、Query)、远程地址和流量权重等条件对请求进行路由匹配。
断言工厂 | 参数 | 匹配条件 | 示例 |
---|---|---|---|
After | datetime | 匹配在指定时间之后的请求 | After=2017-01-20T17:42:47.789-07:00[America/Denver] |
Before | datetime | 匹配在指定时间之前的请求 | Before=2017-01-20T17:42:47.789-07:00[America/Denver] |
Between | datetime1, datetime2 | 匹配在两个指定时间之间的请求 | Between=2017-01-20T17:42:47.789-07:00,2017-01-21T17:42:47.789-07:00 |
Cookie | cookie name, regexp | 匹配指定名称的cookie,并且cookie值符合正则表达式 | Cookie=chocolate, ch.p |
Header | header name, regexp | 匹配指定名称的header,并且header值符合正则表达式 | Header=X-Request-Id, \d+ |
Host | host name patterns | 匹配Host头与指定模式的请求 | Host=**.somehost.org,**.anotherhost.org |
Method | HTTP methods | 匹配指定HTTP方法的请求 | Method=GET,POST |
Path | Spring PathMatcher patterns, matchTrailingSlash | 匹配指定路径模式的请求 | Path=/red/{segment},/blue/{segment} |
Query | param, regexp (optional) | 匹配指定的查询参数,并且参数值符合正则表达式 | Query=green , Query=red, gree. |
RemoteAddr | CIDR-notation (IP addresses) | 匹配请求的远程地址(支持CIDR格式) | RemoteAddr=192.168.1.1/24 |
Weight | group, weight | 根据权重将流量分配到不同的路由 | Weight=group1, 8 , Weight=group1, 2 |
XForwardedRemoteAddr | CIDR-notation (IP addresses) | 匹配基于X-Forwarded-For头的远程地址(支持CIDR格式) | XForwardedRemoteAddr=192.168.1.1/24 |
在配置的时候就像这样添加响应的参数即可,并且官网上边的写的很清楚,这里就不再一个一个的向下配置了
4.3、Filter过滤
4.3.1、概述
https://docs.spring.io/spring-cloud-gateway/docs/4.0.4/reference/html/#gatewayfilter-factories
SpringMVC里面的的拦截器Interceptor,Servlet的过滤器
https://cloud.spring.io/spring-cloud-gateway/reference/html/#gateway-how-it-works
"pre”和"post"分别会在请求被执行前调用和被执行后调用,用来修改请求和响应信息
客户端向 Spring Cloud Gateway 发出请求。如果 Gateway Handler Mapping 确定请求与路由匹配,则将其发送到 Gateway Web Handler。此处理程序通过特定于请求的过滤器链运行请求。过滤器被虚线分开的原因是过滤器可以在发送代理请求之前和之后运行逻辑。所有“前”过滤器逻辑都会执行。然后发出代理请求。发出代理请求后,运行“后”过滤器逻辑。
作用:
- 请求鉴权
- 异常处理
- 记录接口调用时长统计
类型:
- 全局默认过滤器Global Filters
https://docs.spring.io/spring-cloud-gateway/docs/current/reference/html/#global-filters
gateway出厂默认已有的,直接用即可,主要作用于所有的路由
不需要在配置文件中配置,作用在所有的路由上,实现GlobalFilter接口即可
- 单一内置过滤器GatewayFilter
https://docs.spring.io/spring-cloud-gateway/docs/current/reference/html/#gatewayfilter-factories
也可以称为网关过滤器,这种过滤器主要是作用于单一路由或者某个路由分组
- 自定义过滤器
4.3.2、Gateway内置的过滤器
https://docs.spring.io/spring-cloud-gateway/docs/current/reference/html/#gatewayfilter-factories
路由过滤器允许以某种方式修改传入的 HTTP 请求或传出的 HTTP 响应。路由过滤器的作用域是特定的路由。Spring Cloud Gateway 包含许多内置的 GatewayFilter 工厂。
4.3.3、常用的内置过滤器详解
Spring Cloud Gateway内置过滤器分为请求头、请求参数、响应头、路径操作及默认过滤器等,支持对请求和响应的头部、参数、路径进行添加、删除、修改及重定向等操作。
- 请求头相关过滤器:处理请求头的添加、删除或替换操作,支持使用URI变量。
- 请求参数相关过滤器:处理请求参数的添加或删除操作,支持使用URI变量。
- 响应头相关过滤器:处理响应头的添加或删除操作,支持使用URI变量。
- 前缀和路径相关过滤器:处理请求路径的前缀添加、路径修改或重定向操作。
- 其他过滤器:允许为所有路由配置默认的过滤器。
过滤器类别 | 过滤器名称 | 说明 | 示例 |
---|---|---|---|
请求头相关 | AddRequestHeader | 添加请求头,支持URI变量。 | 将X-Request-red: blue 添加到下游请求的头部。 |
RemoveRequestHeader | 移除指定的请求头。 | 移除X-Request-Foo 头。 | |
SetRequestHeader | 替换指定的请求头,支持URI变量。 | 将X-Request-Red 替换为Blue 。 | |
请求参数相关 | AddRequestParameter | 添加请求参数,支持URI变量。 | 将red=blue 添加到下游请求的查询字符串。 |
RemoveRequestParameter | 移除指定的请求参数。 | 移除red 参数。 | |
响应头相关 | AddResponseHeader | 添加响应头,支持URI变量。 | 将X-Response-Red: Blue 添加到下游响应的头部。 |
RemoveResponseHeader | 移除指定的响应头。 | 移除X-Response-Foo 头。 | |
前缀和路径相关 | PrefixPath | 为请求路径添加前缀。 | 为路径/hello 添加前缀/mypath ,结果为/mypath/hello 。 |
RedirectTo | 执行重定向操作,支持包含请求参数。 | 将请求重定向到https://acme.org ,状态码为302。 | |
SetPath | 修改请求路径,支持URI模板。 | 将路径/red/blue 修改为/blue 。 | |
其他 | Default Filters | 为所有路由设置默认过滤器。 | 为所有路由添加X-Response-Default-Red 响应头,并前缀路径为/httpbin 。 |
与断言一样,这里就不在一一的向下列举了,配置的方法都类似
五、环境搭建
SpringBoot+SpringCloud的版本:
<spring.boot.version>3.2.0</spring.boot.version>
<spring.cloud.version>2023.0.0</spring.cloud.version>
注册中心:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-consul-discovery</artifactId>
</dependency>
远程调用:
<!--openfeign-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
Consul
docker pull consul:1.9.6
docker run -d -p 8500:8500 --restart=always --name=consul -v /opt/consul:/consul/data consul:1.9.6 agent -server -bootstrap -ui -node=1 -client='0.0.0.0'
http://192.168.200.129:8500/ui/dc1/services
jdk:
Maven
IDEA
代码汇总:
https://github.com/shixiaochuangjob/markdownfile/tree/main/20240826
https://mp.weixin.qq.com/s?__biz=MzkwOTczNzUxMQ==&mid=2247484774&idx=1&sn=2bedb98dc89c07a37f181c0473e85496&chksm=c1376e2ef640e738eab81b5d85d20e88c8a5773524e66eb4364eac5e5d3d03f18531d6c517a0#rd