SpringCloud GateWay网关(入门)
1、介绍
强烈推荐,看官网文档
①简介
Cloud全家桶里有个重要组件:网关
SpringCloud Gateway基于WebFlux框架
WebFlux底层使用高性能的Reactor模式(异步非阻塞)通信框架Netty
②选择原因
-
1.x版本采用Zuul网关
但是在2.x版本中,zuul升级经常跳票,所以SpringCloud研发了SpringCloud Gateway代替1.x版本
SpringCloud Gateway作为SpringCloud生态的网关,目标是替代Zuul,在SpringCloud2.0以上,没有对Zuul2.0以上进行集成,仍然使用Zuul1.x非Reactor模式的老版本。
-
SpringCloud Gateway属于Spring家族,整合更方便
-
动态路由:能够匹配任何请求属性
-
可以对路由指定Predicate(断言)和Filter(过滤器)
-
Zuul1.基于Servlet2.5使用阻塞架构,不支持任何长连接。Zuul2,SpringCloud没有整合。SpringCloud Gateway吸收Zuul2特点,使用非阻塞架构,支持长连接
③Zuul与Spring Cloud Gateway模型
一.Zuul模型(阻塞式)
使用Servlet2.5
当请求进入Container,会为其绑定一个线程,在并发不高的情况下模型还Ok。但是高并发情况下,线程数会飙升,而线程的资源代价很高贵(线程的上下文切换,内存消耗很大...)严重影响请求处理时间。
二.SpringCloud Gateway模型
在Servlet3.1之后有了异步非阻塞的支持
2、 三大概念
①路由
路由时构建网关的基本模块,它由ID,目标URI,一系列的断言和过滤器组成,如果断言为True,则匹配该路由。
②断言
参考Predicate
开发人员通过匹配HTTP请求中的内容(如请求头,请求参数),如果请求和断言匹配,进行路由
③过滤
在Spring框架中GatewayFilter的实例,使用过滤器,可以在请求被路由前或者之后对请求进行修改。
3、SpringCloud Gateway工作流程
客户端向SpringCloud Gateway发请求,然后Gateway Handler Mapping中找到匹配的路由,将其发送到Gateway Web Handler中。
Handler再通过指定的过滤器链来将请求发送到我们的实际服务执行业务逻辑,然后返回。
过滤器之间用虚线分开,是因为过滤器可能会在发送请求之前(pre)和之后(post)执行逻辑
4、搭建
1.新建模块cloud-gateway-gateway9527
2.pom.xml:
<dependencies> <!--gateway--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-gateway</artifactId> </dependency> <!-- 引用自己定义的api通用包,可以使用Payment支付Entity --> <dependency> <groupId>cn.zko0.cloud</groupId> <artifactId>cloud-api-commons</artifactId> <version>1.0-SNAPSHOT</version> </dependency> <!--eureka client(通过微服务名实现动态路由)--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency> <!--热部署--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <scope>runtime</scope> <optional>true</optional> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies>
3.yml:
将GetWay注册到Eureka上:
server: port: 9527 spring: application: name: cloud-gateway cloud: gateway: routes: - id: payment_route # 路由的id,没有规定规则但要求唯一,建议配合服务名 #匹配后提供服务的路由地址 uri: http://localhost:8001 predicates: - Path=/payment/get/** # 断言,路径相匹配的进行路由 - id: payment_route2 uri: http://localhost:8001 predicates: - Path=/payment/lb/** #断言,路径相匹配的进行路由 eureka: instance: hostname: cloud-gateway-service client: fetch-registry: true register-with-eureka: true service-url: defaultZone: http://eureka7001.com:7001/eureka/
4.启动类:
@SpringBootApplication @EnableEurekaClient public class GatewayMain9527 { public static void main(String[] args) { SpringApplication.run(GatewayMain9527.class, args); } }
5.启动7001(注册中心),8001(Provider)与9527(Gatway)三个工程
6.服务调用测试:
8001调用测试:
9527调用测试:
5、两种配置方式
①配置文件
spring: application: name: cloud-gateway cloud: gateway: routes: - id: payment_route # 路由的id,没有规定规则但要求唯一,建议配合服务名 #匹配后提供服务的路由地址 uri: http://localhost:8001 predicates: - Path=/payment/get/** # 断言,路径相匹配的进行路由 - id: payment_route2 uri: http://localhost:8001 predicates: - Path=/payment/lb/** #断言,路径相匹配的进行路由
②代码注入RouteLocator的Bean
自拟一个需求:
通过Gateway路由到百度贴吧:
这里路由到百度知道存在错误,目前还没有找到原因,由于Gateway一般用于内网的转发,所以没有细究,主要学习Gateway的配置方式
@Configuration public class GatwayConfig { @Bean public RouteLocator customRouteLocator(RouteLocatorBuilder routeLocatorBuilder){ RouteLocatorBuilder.Builder routes = routeLocatorBuilder.routes(); /*routes.route("path_route_angenin", //id r -> r.path("/zhidao") //访问 http://localhost:9527/zhidao .uri("https://zhidao.baidu.com/")); //就会转发到*/ routes.route("path_route_angenin2", //id r -> r.path("/tieba") //访问 http://localhost:9527/tieba .uri("https://tieba.baidu.com/index.html")); //就会转发到 return routes.build(); } }
6、动态路由
①产生原因
在前面我们的配置都是写死了uri
8001和8002都是payment,如果后面我们对paymen服务进行扩容,出现了8003,8004等,那么这种方式就没有办法进行动态的调整了
②配置
通过微服务名实现动态路由
-
开启从注册中心动态创建路由的功能,利用微服务名称进行路由(默认false)
-
把写死的uri替换为服务名
lb:是指路由的一种通信协议,它实现了负载均衡通信功能
总配置文件:
server: port: 9527 spring: application: name: cloud-gateway cloud: gateway: discovery: locator: enabled: true #开启从注册中心动态创建路由的功能,利用微服务名称进行路由(默认false) routes: - id: payment_route # 路由的id,没有规定规则但要求唯一,建议配合服务名 #匹配后提供服务的路由地址 uri: lb://cloud-payment-service predicates: - Path=/payment/get/** # 断言,路径相匹配的进行路由 # - id: payment_route2 # uri: lb://cloud-payment-service # predicates: # - Path=/payment/xxxx #断言,路径相匹配的进行路由 eureka: instance: hostname: cloud-gateway-service client: fetch-registry: true register-with-eureka: true service-url: defaultZone: http://eureka7001.com:7001/eureka/
启动测试:
启动eureka注册中心,payment8001和8002,9827gateway
接口调用测试:成功
7、路由断言
之前我们的断言仅仅使用了uri的匹配
Springcloud Gateway还提供了很多其他断言判断条件:
①The After Route Predicate Factory
时间级别还有:
- The Before Route Predicate Factory
- The Between Route Predicate Factory
配置:
测试类,获取当前的时间:
public class Test { public static void main(String[] args) { ZonedDateTime now = ZonedDateTime.now(); System.out.println(now); } }
通过上图我们能获得当前的时间
设置after断言判断,让当前时间在设置事件后,该路由才能生效
spring: application: name: cloud-gateway cloud: gateway: discovery: locator: enabled: true #开启从注册中心动态创建路由的功能,利用微服务名称进行路由(默认false) routes: - id: payment_route # 路由的id,没有规定规则但要求唯一,建议配合服务名 #匹配后提供服务的路由地址 uri: lb://cloud-payment-service predicates: - Path=/payment/get/** # 断言,路径相匹配的进行路由 - After=2023-01-17T15:23:19.987+08:00[Asia/Shanghai]
重启测试:
由于时间未到after之后,所以路由未生效
②The Cookie Route Predicate Factory
下面的介绍来自官网,看官网就OK了
cookie 路由断言工厂采用两个参数,即 cookie 名称和正则表达式。 此谓词匹配具有给定名称且其值与正则表达式匹配的 Cookie。 以下示例配置 cookie 路由断言工厂:
配置:
spring: application: name: cloud-gateway cloud: gateway: discovery: locator: enabled: true #开启从注册中心动态创建路由的功能,利用微服务名称进行路由(默认false) routes: - id: payment_route # 路由的id,没有规定规则但要求唯一,建议配合服务名 #匹配后提供服务的路由地址 uri: lb://cloud-payment-service predicates: - Path=/payment/get/** # 断言,路径相匹配的进行路由 #- After=2023-01-17T15:23:19.987+08:00[Asia/Shanghai] - Cookie=username,fuckU
重启测试:
带Cookie调用,成功:
不带Cookie调用,或者Cookie错误,失败:
③The Header Route Predicate Factory
标头路由断言工厂采用两个参数,即标头名称和正则表达式。 此断言与具有给定名称的标头匹配,该标头的值与正则表达式匹配。 以下示例配置标头路由断言:
配置测试:
spring: application: name: cloud-gateway cloud: gateway: discovery: locator: enabled: true #开启从注册中心动态创建路由的功能,利用微服务名称进行路由(默认false) routes: - id: payment_route # 路由的id,没有规定规则但要求唯一,建议配合服务名 #匹配后提供服务的路由地址 uri: lb://cloud-payment-service predicates: - Path=/payment/get/** # 断言,路径相匹配的进行路由 - Header=X-Request-Id, \d+ #- After=2023-01-17T15:23:19.987+08:00[Asia/Shanghai] #- Cookie=username,fuckU
测试:
当Header中X-Request-Id的value为正整数,路由才能生效
④还有很多:略
参考Spring官网提供的文档即可:
8、Gateway Filter
路由过滤器允许以某种方式修改传入的HTTP请求或传出的HTTP响应。路由过滤器只能指定路由使用
①生命周期
- pre(前
- post(后
②种类
一.单一的Gateway Filter
用的比较少,略
二.全局过滤器
自定义全局GlobalFilter
新建config包,自定义全局过滤器:该过滤器能够通过检验请求参数是否包含username,来设置是否过滤请求:
@Slf4j @Component public class MyLogGateWayFilter implements GlobalFilter, Ordered { @Override public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { log.info("**************come in MyLogGatewayFilter{}",new Date()); String uname = exchange.getRequest().getQueryParams().getFirst("uname"); if (uname==null){ log.info("*****用户名为null,非法"); exchange.getResponse().setStatusCode(HttpStatus.NOT_ACCEPTABLE); return exchange.getResponse().setComplete(); } return chain.filter(exchange); } @Override //数字越小Filter的优先级越高 public int getOrder() { return 0; } }
重启,测试:
请求附带参数,uname=1,成功
请求不附带参数,失败:
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?