7.Gateway
8.Gateway
8.1.介绍
8.1.1.网关介绍
网关是微服务最边缘的服务,直接暴露给用户,用来做用户和微服务的桥梁
没有网关:客户端直接访问我们的微服务,会需要在客户端配置很多的ip:port
,如果user-service
并发比较大,则无法完成负载均衡。
有网关:客户端访问网关,网关来访问微服务,(网关可以和注册中心整合,通过服务名称找到目标的ip:prot
),这样只需要使用服务名称即可访问微服务,可以实现负载均衡,可以实现token
拦截,权限验证,限流等操作。
8.1.2.Gateway简介
Gateway
是SpringCloud
官方提供的用来取代zuul
(netflix)的新一代网关组件(zuul的本质是一组过滤器,根据自定义的过滤器顺序来执行)
基于spring5.x、springboot2.x 和ProjectReactor
等技术。
目地是让路由更加简单、灵活,还提供了一些强大的过滤器功能,例如:熔断、限流、重试,自义定过滤器等token校验ip黑名单等
SpringCloudGateway
作为SpringCloud
生态的网关,目标是替代Zuul
,在SpringCloud2.0
以上的版本中,没有对新版本的zuul2.0
以上的最新高性能版本进行集成,仍然还是使用的zuul1.x
,非Reactor
模式的老版本。
为了提升网关的性能,SpringCloudGateway
是基于webFlux
框架实现的,webFlux
框架底层则使用了高性能的Reactor
模式通信框架的Netty
8.1.3.特征与功能
1.建立在SpringFramework5
,ProjectReactor
和SpringBoot2.0
之上
2.能够匹配任何请求属性上的路由
3.谓词和过滤器特定于路由
4.Hystrix
断路器集成。
5.SpringCloudDiscoveryClient
集成
6.易于编写的谓词和过滤器
7.请求速率限制
8.路径改写
8.1.4.工作流程
1客户端向springcloudGateway
发出请求,然后在GatewayHandlerMapping
中找到与其请求相匹配的路由,将其发送到GatewayWebHandle
Handler
再通过指定的过滤器来将请求发送到我们实际的服务的业务逻辑,然后返回。
过滤器之间用虚线分开是因为过滤器可能会在发送爱丽请求之前【pre】或之后【post】执行业务 逻辑,对其进行加强或处理。
Filter在【pre】类型的过滤器可以做参数校验、权限校验、流量监控、日志输出、协议转换等
在【post】类型的过滤器中可以做响应内容、响应头的修改、日志的输出,流量监控等有着非常重要的作用。
总结:核心逻辑就是路由转发+执行过滤器链
8.1.5.三大核心概念
①Route(路由)
路由信息的组成: 由一个ID、一个目的URL、一组断言工厂、一组Filter组成。
如果路由断言为真,说明请求URL和配置路由匹配。
②Predicate(断言)
SpringCloudGateway
中的断言函数输入类型是Spring5.0
框架中的 ServerWebExchange
。
SpringCloudGateway
的断言函数允许开发者去定义匹配来自于HttpRequest
中的任何信息比如请求头和参数
③Filter(过滤)
一个标准的SpringWebFilter
由servlet
、listener
、filter
以及interceptor
组成。
SpringCloudGateway
中的Filter
分为两种类型的 Filter
- GatewayFilter:针对某一个路由(路径)
- GlobalFilter:针对全局
8.1.6.Nginx与Gateway的区别
Nginx
在做路由、负载均衡、限流之前都有修改nginx.conf
的配置文件,把需要负载均衡, 路由,限流的规则加在里面。(nginx做tomcat的负载均衡)
gateway
则是自动的负载均衡和路由,gateway
和eureka
高度集成,实现 自动的路由,和Ribbon
结合,实现了负载均衡,gateway
也能轻易的实现限流和权限验证。
Nginx
比gateway
的性能高一点。
本质区别就是:
Nginx
:服务器级别的Gateway
:项目级别的
8.2.快速入门
没有实现过滤功能
8.2.1.搭建login-service
①选择依赖
只选择web
即可。
②修改配置文件
③添加controller类
8.2.2.搭建Gateway-server
①选择依赖
只需要选择gateway
即可。
②修改配置文件
8.2.3.搭建eureka-server
8.2.4.访问测试
返回出现token即为成功。
8.3.路由
8.3.1.配置方式之代码方式
访问测试:localhost:80/path路径
8.3.2.配置方式之yml方式
8.3.3.动态路由
默认情况下Gateway
会根据注册中心的服务列表,以注册中心上微服务名为路径创建动态路由进行转发,从而实现动态路由的功能
需要注意的是uri的协议为lb(load Balance),表示启用Gateway
的负载均衡功能。
lb://服务名称
是SpringCloudGateway
在微服务中自动为我们创建的负载均衡uri
例:lb://login-service
8.3.4.动态路由使用
改造刚才的例子
Gateway-server改造:
login-service改造:
访问测试:http://localhost/login-service/login
http://localhost:80/服务名称/path路径
出现token即为成功。
8.4.断言
断言就是一些布尔表达式,满足条件的返回true,不满足的返回false。
SpringCloudGateway
将路由作为SpringWebFluxHandlerMapping
基础架构的一部分进行匹配。
SpringCloudGateway
包括许多内置的路由断言工厂。
所有这些断言都与HTTP请求的不同属性匹配。可以将多个路由断言可以组合使用SpringCloudGateway
创建对象时,使用RoutePredicateFactory
创建 Predicate
对象,Predicate
对象可以赋值给Route
。
配置规则
使用
spring:
cloud:
gateway:
enabled: true #开启网关,默认是开启的
routes: #设置路由,注意是数组,可以设置多个,按照 id 做隔离
- id: user-service #路由 id,没有要求,保持唯一即可
uri: lb://provider #使用 lb 协议 微服务名称做负均衡
predicates: #断言匹配
- Path=/info/** #和服务中的路径匹配,是正则匹配的模式
- After=2020-01-20T17:42:47.789-07:00[Asia/Shanghai] #此断言匹配发生在指定日期时间之后的请求,ZonedDateTime dateTime=ZonedDateTime.now()获得
- Before=2020-06-18T21:26:26.711+08:00[Asia/Shanghai] #此断言匹配发生在指定日期时间之前的请求
-Between=2020-06-18T21:26:26.711+08:00[Asia/Shanghai],2020-06-18T21:32:26.711+08:00[Asia/Shanghai]
#此断言匹配发生在指定日期时间之间的请求
- Cookie=name,xiaobai #Cookie 路由断言工厂接受两个参数,Cookie 名称和 regexp(一个 Java 正则表达式)。此断言匹配具有给定名称且其值与正则表达式匹配的 cookie
- Header=token,123456 #头路由断言工厂接受两个参数,头名称和 regexp(一个 Java 正则表达式)。此断言与具有给定名称的头匹配,该头的值与正则表达式匹配。
- Host=**.bai*.com:* #主机路由断言工厂接受一个参数:主机名模式列表。该模式是一个 ant 样式的模式。作为分隔符。此断言匹配与模式匹配的主机头
- Method=GET,POST #方法路由断言工厂接受一个方法参数,该参数是一个或多个参数:要匹配的 HTTP 方法
- Query=username,cxs #查询路由断言工厂接受两个参数:一个必需的 param 和一个可选的 regexp(一个 Java 正则表达式)。
- RemoteAddr=192.168.1.1/24 #RemoteAddr 路由断言工厂接受一个源列表(最小大小 1),这些源是 cidr 符号(IPv4 或 IPv6)字符串,比如 192.168.1.1/24(其中 192.168.1.1 是 IP 地址,24 是子网掩码)
还有一个访问权重的设置,比如说:
80%的请求,由https://weighthigh.org 这个 url 去处理
20%的请求,由https://weightlow.org 去处理
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
8.5.过滤
gateway
的过滤器和Servlet
的过滤器功能差不多,路由过滤器可以用于修改进入Http请求和返回Http响应
8.5.1.分类
生命周期分类
pre:在业务逻辑之前
post:在业务逻辑之后
种类分类
GatewayFilter
需要配置某个路由才能过滤。
如果需要使用全局路由,需要配置DefaultFilters
。
GlobalFilter
全局过滤器,不需要配置路由,系统初始化作用到所有路由上 全局过滤器
8.5.2.自定义过滤
在上面的测试中添加一个类测试即可。
8.5.3.IP认证拦截
修改上面的自定义过滤类即可。
8.6.限流
限制一段时间内,用户访问资源的次数,减轻服务器压力。
限流分为
1.IP限流(一段时间内只能访问x次,超过则限制不让访问,过一段时间才可继续访问)
2.请求量限流(只要在一段时间内(窗口期),请求次数达到阀值,就直接拒绝后面来的访问了, 过一段时间才可以继续访问)(粒度可以细化到一个api/url,一个服务)
结合redis实现
①添加依赖
SpringCloudGateway
已经内置了一个 RequestRateLimiterGatewayFilterFactory
。
RequestRateLimiterGatewayFilterFactory
的实现依赖于Redis
,所以需要引入spring-boot-starter-data-redis-reactive
这个依赖。
<!--限流要引入 Redis-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis-reactive</artifactId>
</dependency>
②添加配置
server:
port: 80
spring:
application:
name: gateway-server
cloud:
gateway:
routes:
- id: user-service-router
uri: lb://login-service
predicates:
- Path=/login
filters:
- name: RequestRateLimiter
args:
key-resolver: '#{@hostAddrKeyResolver}' #用于限流的键的解析器的Bean对象的名字。使用SpEL表达式根#{@beanName}从Spring容器中获取Bean对象
redis-rate-limiter.replenishRate: 1 #令牌桶每秒填充平均速率
redis-rate-limiter.burstCapacity: 3 #令牌桶容量
redis: #redis 的配置
host: localhost
port: 6379
database: 0
eureka:
instance:
instance-id: ${spring.application.name}:${server.port}
prefer-ip-address: true
client:
service-url:
defaultZone: http://localhost:8761/eureka
③添加config类
@Configuration
public class RequestRateLimiterConfig {
/*
* IP 限流
* 把用户的 IP 作为限流的 Key
*/
@Bean
@Primary
public KeyResolver hostAddrKeyResolver() {
return (exchange) -> Mono.just(exchange.getRequest().getRemoteAddress().getHostName());
}
/**
* 用户 id 限流
* 把用户 ID 作为限流的 key
*/
@Bean
public KeyResolver userKeyResolver() {
return exchange -> Mono.just(exchange.getRequest().getQueryParams().getFirst("userId"));
}
/**
* 请求接口限流
* 把请求的路径作为限流 key
*/
@Bean
public KeyResolver apiKeyResolver() {
return exchange -> Mono.just(exchange.getRequest().getPath().value());
}
}
④访问测试
快速访问多次:http://localhost/login,之后出现429错误即为成功
8.7.跨域
代码实现
@Configuration
public class CorsConfig {
@Bean
public CorsWebFilter corsFilter() {
CorsConfiguration config = new CorsConfiguration();
config.addAllowedMethod("*");
config.addAllowedOrigin("*");
config.addAllowedHeader("*");
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(new PathPatternParser());
source.registerCorsConfiguration("/**", config);
return new CorsWebFilter(source);
}
}
配置文件实现
spring:
cloud:
gateway:
globalcors:
corsConfigurations:
'[/**]': // 针对哪些路径
allowCredentials: true #可以携带cookie
allowedHeaders: '*'
allowedMethods: '*'
allowedOrigins: '*
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 【自荐】一款简洁、开源的在线白板工具 Drawnix