服务网关-GateWay-微服务核心组件【分布式微服务笔记05】
服务网关-GateWay
引出GateWay
当我们后端的服务部署在差别的ip和端口上,存在一些问题:
- 前端项目必要维护差别的后端服务ip/访问接口,非常贫苦
- 如果调用的是后端的集群服务,存在负载均衡问题
- 没有断言以及过滤机制
- 因此我们必要网关服务
引入GateWay后项目
- 网关服务对外提供统一的调用接口,根据不用的哀求url,转发到对应的后端服务【必要配置】
- 实现负载均衡
- 限流
- 熔断降级
- 鉴权
GateWay网络拓扑图
GateWay根本介绍
- Gateway 是在Spring 生态系统之上构建的API 网关服务,基于Spring ,Spring Boot 和Project Reactor 等技术。
- Gateway 旨在提供一种简朴而有用的方式来对API 进行路由,以及提供一些强盛的过滤器功能,例如∶熔断、限流、重试等。
GateWay核心功能
Gateway 和Zuul 区别
- SpringCloud Gateway 作为Spring Cloud 生态系统中的网关,目标是替代Zuul
- SpringCloud Gateway 是基于Spring WebFlux 框架实现的
- Spring WebFlux 框架底层则使用了高性能的Reactor 模式通信框架Netty , 提拔了网关性能
Gateway 特性
Spring Cloud Gateway 基于Spring Framework(支持Spring WebFlux),Project Reactor 和 Spring Boot 进行构建,具有如下特性:
- 动态路由
- 可以对路由指定Predicate(断言)和Filter(过滤器)
- 集成Hystrix的断路器功能
- 集成Spring Cloud 服务发现功能
- 哀求限流功能
- 支持路径重写
Gateway 根本原理
Route(路由)
路由是构建网关的根本模块,它由ID,目标URI,一系列的断言和过滤器组成,如果断言为true 则匹配该路由
Predicate(断言)
- 对HTTP 哀求中的全部内容(例如哀求头或哀求参数)进行匹配,如果哀求与断言相匹配则进行路由,如果Http 哀求的路径不匹配, 则不进行路由转发.
Filter(过滤)
- 使用过滤器,可以在哀求被路由前或者之后对哀求进行处理【在对Http 哀求断言匹配乐成后, 可以通过网关的过滤机制, 对Http 哀求处理】
GateWay工作机制
- 客户端向Spring Cloud Gateway 发出哀求。然后在Gateway Handler Mapping 中找到与哀求相匹配的路由【断言】,将其发送到Gateway Web Handler。
- Handler 再通过指定的过滤器链来将哀求发送到我们实际的服务执行业务逻辑,然后返回。
- 过滤器之间用虚线分开是因为过滤器可能会在发送署理哀求之前("pre")或之后("post")执行业务逻辑。
- Filter 在"pre"类型的过滤器可以做参数校验、权限校验、流量监控、日志输出、协议转换等,
- 在"post"类型的过滤器中可以做响应内容、响应头的修改,日志的输出,流量监控等有着非常重要的作用。
GateWay代码实现
必要将服务斲丧方升级成服务网关
- 引入gateway-starter网关场景启动器
- <dependency>
- <groupId>org.springframework.cloud</groupId>
- <artifactId>spring-cloud-starter-gateway</artifactId>
- </dependency>
复制代码 - Gateway路由配置两种【application.yml和配置类】
- 配置类
- //配置类-配置路由
- @Configuration
- public class GateWayRoutesConfig {
- /*
- Function<PredicateSpec, Route.AsyncBuilder> fn
- :函数式接口,接收的类型是PredicateSpec,返回的类型是 Route.AsyncBuilder
- r -> r.path("/member/get/**")
- .uri("http://localhost:10001") 是Lambda表达式
- */
- @Bean
- public RouteLocator myRouteLocator04(RouteLocatorBuilder routeLocatorBuilder){
- RouteLocatorBuilder.Builder routes = routeLocatorBuilder.routes();
- /*
- route 源码:
- public Builder route(String id, Function<PredicateSpec, Route.AsyncBuilder> fn) {
- Route.AsyncBuilder routeBuilder = (Route.AsyncBuilder)fn.apply((new RouteSpec(this)).id(id));
- this.add(routeBuilder);
- return this;
- }
- */
- return routes.route("member_route04",r -> r.path("/member/get/**")
- .uri("http://localhost:10001"))
- .build();
- }
- }
复制代码 - application.yml【推荐】
- spring:
- application:
- name: e-commerce-gateway-20000 #配置应用的名称
- cloud:
- gateway:
- discovery:
- locator:
- enabled: true #启用 DiscoveryClient 服务发现
- #配置路由,可以配置多个路由 放在List<RouteDefinition> routes 中
- routes:
- - id: member_route01 #路由的ID
- # uri: http://localhost:10001 #路由目标接口的ip 和 端口
- uri: lb://member-service-provider #lb:// 是协议名【Load Balance负载均衡的协议名】 member-service-provider 是服务名小写
- predicates: #断言,可以多种形式
- - Path=/member/get/**
- - id: member_route02 #路由的ID
- # uri: http://localhost:10001 #路由目标接口的ip 和 端口
- uri: lb://member-service-provider #lb: 是协议名【Load Balance负载均衡的协议名】 member-service-provider :服务名小写
- predicates: #断言,可以多种形式
- - Path=/member/save
复制代码
更改GateWay负载均衡算法
只必要添加配置类即可【默认的轮询算法足够应对大多业务】- //配置自己的负载均衡算法
- @Configuration
- public class RibbonRule {
- // 配置注入负载均衡算法
- @Bean
- public IRule myRibbonRule(){
- return new RandomRule();//new 的就是负载均衡算法 ,自己选择,这里是随机算法
- }
- }
复制代码 Predicate-断言
Predicate 就是一组匹配规则,当哀求匹配乐成,就执行对应的Route;当匹配失败,放弃处理/转发
Route Predicate factory - 路由断言工厂
- Spring Cloud Gateway包括许多内置的Route Predicate工厂, 全部这些Predicate都与HTTP哀求的差别属性匹配【可以组合使用】,来进行差别的断言.【比如说Cookie,消息头,时间,路径......】
- Spring Cloud Gateway 创建Route 对象时,使用RoutePredicateFactory 创建Predicate对象,Predicate 对象可以赋值给Route。
- 全部这些谓词都匹配HTTP哀求的差别属性。多种谓词工厂可以组合。【谓词就是匹配的标准】
After Router Predicate-根据时间之后匹配
例如 只有2024-7-26 11:11:11 之后的哀求才进行匹配/转发, 不满足该条件的,不处理- spring:
- application:
- name: e-commerce-gateway-20000 #配置应用的名称
- cloud:
- gateway:
- discovery:
- locator:
- enabled: true #启用 DiscoveryClient 服务发现
- routes:
- - id: member_route01 #路由的ID
- #lb: 是协议名【Load Balance负载均衡的协议名】 member-service-provider :服务名小写
- uri: lb://member-service-provider
- predicates: #断言,可以多种形式
- - Path=/member/get/**
- - After=2024-07-26T11:11:11.000+08:00[Asia/Shanghai] #需要请求满足这个时间之后
复制代码 Before Route Predicate-根据时间之前匹配
例如 只有2024-7-26 11:11:11 之前的哀求才进行匹配/转发, 不满足该条件的,不处理- spring:
- application:
- name: e-commerce-gateway-20000 #配置应用的名称
- cloud:
- gateway:
- discovery:
- locator:
- enabled: true #启用 DiscoveryClient 服务发现
- routes:
- - id: member_route01 #路由的ID
- #lb: 是协议名【Load Balance负载均衡的协议名】 member-service-provider :服务名小写
- uri: lb://member-service-provider
- predicates: #断言,可以多种形式
- - Path=/member/get/**
- - Before=2024-07-26T11:11:11.000+08:00[Asia/Shanghai] #需要请求满足这个时间之前
复制代码 Between Route Predicate-根据时间之间匹配
例如 只有2024-7-26 11:11:11 和 2024-7-29 11:11:11 之间的哀求才进行匹配/转发, 不满足该条件的,不处理- spring:
- application:
- name: e-commerce-gateway-20000 #配置应用的名称
- cloud:
- gateway:
- discovery:
- locator:
- enabled: true #启用 DiscoveryClient 服务发现
- routes:
- - id: member_route01 #路由的ID
- #lb: 是协议名【Load Balance负载均衡的协议名】 member-service-provider :服务名小写
- uri: lb://member-service-provider
- predicates: #断言,可以多种形式
- - Path=/member/get/**
- - Between=2024-07-26T11:11:11.000+08:00[Asia/Shanghai],2024-07-29T11:11:11.000+08:00[Asia/Shanghai] #需要请求满足这个时间之间
复制代码 Cookie Route Predicate-根据Cookie匹配
哀求带有Cookie,并且键值对有一定要求【值 也可以是一个正则表达式】- spring:
- application:
- name: e-commerce-gateway-20000 #配置应用的名称
- cloud:
- gateway:
- discovery:
- locator:
- enabled: true #启用 DiscoveryClient 服务发现
- routes:
- - id: member_route01 #路由的ID
- #lb: 是协议名【Load Balance负载均衡的协议名】 member-service-provider :服务名小写
- uri: lb://member-service-provider
- predicates: #断言,可以多种形式
- - Path=/member/get/**
- - Cookie=name,zy #键:name 值: zy 【值 也可以是一个正则表达式】
复制代码 Header Route Predicate-根据哀求头匹配
哀求头Header 有Authorization, 并且值admin才匹配/断言乐成- spring:
- application:
- name: e-commerce-gateway-20000 #配置应用的名称
- cloud:
- gateway:
- discovery:
- locator:
- enabled: true #启用 DiscoveryClient 服务发现
- routes:
- - id: member_route01 #路由的ID
- #lb: 是协议名【Load Balance负载均衡的协议名】 member-service-provider :服务名小写
- uri: lb://member-service-provider
- predicates: #断言,可以多种形式
- - Path=/member/get/**
- - Header=Authorization,admin #Authorization是请求头中的一个属性,【值 也可以是一个正则表达式】
复制代码 Host Route Predicate-根据主机名匹配
哀求Host 满足一定要求 才匹配/断言乐成- spring:
- application:
- name: e-commerce-gateway-20000 #配置应用的名称
- cloud:
- gateway:
- discovery:
- locator:
- enabled: true #启用 DiscoveryClient 服务发现
- routes:
- - id: member_route01 #路由的ID
- #lb: 是协议名【Load Balance负载均衡的协议名】 member-service-provider :服务名小写
- uri: lb://member-service-provider
- predicates: #断言,可以多种形式
- - Path=/member/get/**
- - Host=**.zy.**,**.zy88.** #【可以有多个,用逗号间隔】
复制代码 Method Route Predicate-根据哀求方式匹配
哀求方式满足一定要求【post/get/delete......】 才匹配/断言乐成- spring:
- application:
- name: e-commerce-gateway-20000 #配置应用的名称
- cloud:
- gateway:
- discovery:
- locator:
- enabled: true #启用 DiscoveryClient 服务发现
- routes:
- - id: member_route01 #路由的ID
- #lb: 是协议名【Load Balance负载均衡的协议名】 member-service-provider :服务名小写
- uri: lb://member-service-provider
- predicates: #断言,可以多种形式
- - Path=/member/get/**
- - Method=POST,GET #【可以有多个,用逗号间隔】
复制代码 Path Route Predicate-根据路径匹配
路径满足一定要求 才匹配/断言乐成- spring:
- application:
- name: e-commerce-gateway-20000 #配置应用的名称
- cloud:
- gateway:
- discovery:
- locator:
- enabled: true #启用 DiscoveryClient 服务发现
- routes:
- - id: member_route01 #路由的ID
- #lb: 是协议名【Load Balance负载均衡的协议名】 member-service-provider :服务名小写
- uri: lb://member-service-provider
- predicates: #断言,可以多种形式
- - Path=/member/get/**,/member/save #【可以有多个路径】
复制代码 Query Route Predicate-根据哀求参数匹配
- spring:
- application:
- name: e-commerce-gateway-20000 #配置应用的名称
- cloud:
- gateway:
- discovery:
- locator:
- enabled: true #启用 DiscoveryClient 服务发现
- routes:
- - id: member_route01 #路由的ID
- #lb: 是协议名【Load Balance负载均衡的协议名】 member-service-provider :服务名小写
- uri: lb://member-service-provider
- predicates: #断言,可以多种形式
- - Path=/member/get/** #【可以有多个路径】
- - Query=email, [\w-]+@([a-zA-Z]+\.)+[a-zA-Z]+ #【可以是正则表达式】
复制代码 RemoteAddr Route Predicate-根据远程地址匹配
调用端远程地址是否满足 来判定- spring:
- application:
- name: e-commerce-gateway-20000 #配置应用的名称
- cloud:
- gateway:
- discovery:
- locator:
- enabled: true #启用 DiscoveryClient 服务发现
- routes:
- - id: member_route01 #路由的ID
- #lb: 是协议名【Load Balance负载均衡的协议名】 member-service-provider :服务名小写
- uri: lb://member-service-provider
- predicates: #断言,可以多种形式
- - Path=/member/get/** #【可以有多个路径】
- - RemoteAddr=127.0.0.1 #调用端的远程地址
复制代码 Filter-过滤器
- 路由过滤器可用于修改进入的HTTP哀求和返回的HTTP响应
- Spring Cloud Gateway 内置了多种路由过滤器,他们都由GatewayFilter的工厂类来产生
GatewayFilter
GatewayFilter是GatewayFilter的工厂类来产生内置Filter,有31种- spring:
- application:
- name: e-commerce-gateway-20000 #配置应用的名称
- cloud:
- gateway:
- discovery:
- locator:
- enabled: true #启用 DiscoveryClient 服务发现
- routes:
- - id: member_route01 #路由的ID
- uri: lb://member-service-provider
- predicates: #断言,可以多种形式
- - Path=/member/get/** #【可以有多个路径】
- filters:
- - AddRequestParameter=role, admin #过滤器可以有多个
- - AddRequestParameter=address, beijing
复制代码 自界说过滤器GlobalFilter
开发直接使用GatewayFilter 较少,一般使用自界说过滤器- @Component
- public class CustomGateWayFilter implements GlobalFilter, Ordered {
- //filter 方法写的就是过滤业务
- @Override
- public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
- //获取对应的参数值
- //getFirst 请求的是键username获取到的值的集合的第一个
- String username = exchange.getRequest().getQueryParams().getFirst("username");
- String pwd = exchange.getRequest().getQueryParams().getFirst("pwd");
- if (!("zy".equals(username) && "123456".equals(pwd))){
- exchange.getResponse().setStatusCode(HttpStatus.NOT_ACCEPTABLE);//设置状态码
- return exchange.getResponse().setComplete();
- }
- //放行
- return chain.filter(exchange);
- }
- //order 表示过滤器执行的顺序,数字越小,优先级越高
- @Override
- public int getOrder() {
- return 0; //指定优先级
- }
- }
复制代码 免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |