Gateway前置
-
Zuul是路由网关,但是现在更趋向于使用Gateway(新一代网关)。Spring研发的Gateway。
-
cloud全家桶中有一个很重要的组件就是网关,在1.x版本中采用的Zuul网关;但在2.x版本中,zuul的升级一直跳票,最后springcloud则自己研发了一个网关代替了zuul。即gateway是原zuul1.x版的替代。
-
SpringCloud Gateway,是基于Web’Flux框架实现的,而WebFlux框架底层则使用了高性能的Reactor模式通信框架Netty。
-
SpringCloud Gateway,是为了提供统一的路由方式,且基于Filer链的方式提供了网关基本的功能,例如:安全、监控/指标,和限流、反向代理、鉴权、熔断、日志监控。
-
网关可以视为各个微服务的入口,具体可以看ppt图片。
-
客户端向Spring Cloud Gateway发出请求,然后在Gateway Handler Mapping中找到与请求相匹配的路由,将其发送到Gateway Web Handler。Handler再通过指定的过滤器链来将请求发送到我们实际的服务执行业务逻辑,然后返回。过滤器之间用虚线分开,是因为过滤器可能会在发送代理请求之前(“pre”)或之后(“post”)执行业务逻辑。
-
Filter在“pre”类型的过滤器可以做参数校验、权限校验、流量监控、日志输出、协议转换等。在“post”类型的过滤器中,可以做响应内容、响应头的修改,日志的输出,流量监控等,有着非常重要的作用。
-
核心逻辑:路由转发+执行过滤链
版本说明
- cloud Hoxton.SR1
- boot 2.2.2RELEASE
- cloud alibaba 2.1.0 RELEASE
- java java8
- Maven 3.5以上
- Mysql 5.7以上
Gateway
网关路由的第一种配置方式
-
在YML中配置,操作步骤:
-
gateway网关服务,不需要web和actuator,所以9527要在POM中删除这两个依赖。
-
新建module:cloud-gateway-gateway9527
-
修改POM、YML、无业务类
server: port: 9527 spring: application: name: cloud-gateway cloud: gateway: routes: - id: payment_routh #payment_route 路由的ID,没有固定规则,但要求唯一,建议配合服务名 uri: http://localhost:8001 #匹配后提供服务的路由地址 predicates: - Path=/payment/get/** #断言,路径相匹配的进行路由 - id: payment_routh2 #payment_route uri: http://localhost:8001 predicates: - Path=/payment/lb/** #断言,路径相匹配,则进行路由 eureka: instance: hostname: cloud-gateway-service client: #服务提供者provider,注册进eureka服务列表内 service-url: register-with-eureka: true fetch-registry: true #表示是否从eureka获取到注册信息 defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka
-
添加主启动类;
@SpringBootApplication @EnableEurekaClient public class GateWayMain9527 { public static void main(String[] args) { SpringApplication.run(GateWayMain9527.class,args); } }
-
让9527网关做路由映射:
- 确认cloud-provider-payment8001的controller的访问地址:①get;②lb;
- 我们不想暴露8001端口(调用cloud-provider-payment8001),希望在8001外面套一层9527;
-
测试:启动7001、7002、启动cloud-provider-payment8001、启动9527网关;
- 添加网关前,访问:http://localhost:8001/payment/get/1
- 添加网关后,访问:http://localhost:9527/payment/get/1
-
网关路由的第二种配置方式
-
代码中注入RouteLocator的Bean
-
创建一个配置类,然后添加如下具体内容:
@Configuration public class GateWayConfig { /** * 配置了一个id为path_route_atguigu的路由规则 * 当访问地址http://localhost:9527/guonei时,会转发到地址http://news.baidu.com/guonei * @param routeLocatorBuilder * @return */ @Bean public RouteLocator customRouteLocator(RouteLocatorBuilder routeLocatorBuilder){ RouteLocatorBuilder.Builder routes = routeLocatorBuilder.routes(); routes.route("path_route_atguigu", r -> r.path("/guonei"). uri("http://news.baidu.com/guonei")).build(); return routes.build(); } }
网关实现动态路由
-
默认情况下Gateway会根据注册中心注册的服务列表,以注册中心上微服务名为路径,创建动态路由进行转发,从而实现动态路由的功能。
-
启动7001/7002,和两个微服务提供者8001和8002
-
修改9527的配置文件内容:
#下面时配置动态路由的内容 cloud: gateway: discovery: locator: enabled: true #开启从注册中心动态创建路由的功能,利用微服务名称进行路由 routes: - id: payment_routh uri: lb://cloud-payment-service #匹配提供服务的路由地址 predicates: - Path=/payment/get/** - id: payment_routh2 uri: lb://cloud-payment-service #匹配提供服务的路由地址 predicates: - Path=/payment/lb/**
-
测试地址:http://localhost:9527/payment/lb,实现结果为,在8001端口和8002端口两者间切换。
断言(predicate)
-
after route predicate:在…时间之后,访问才能断言成功。而具体时间,由下面这个方法可以得出:
ZonedDateTime zbj = ZonedDateTime.now();//默认时区 System.out.println(zbj); //2020-12-15T20:09:16.589+08:00[Asia/Shanghai] 当前时间
示例(直接在yml配置文件中配置即可):
- id: payment_routh2 uri: lb://cloud-payment-service #匹配提供服务的路由地址 predicates: - Path=/payment/lb/** - After=2020-12-15T20:09:16.589+08:00[Asia/Shanghai]
可以用在,给某个系统上线的时间,做一个定时功能,即这个系统,晚上八点之后才上线(才能访问)。
-
before route predicate
-
between route predicate
-
cookie route predicate
-
Cookie Route Predicate需要两个参数,一个时Cookie name,一个是正则表达式。路由规则会通过获取对应的Cookie name值和正则表达式去匹配,如果匹配上,就会执行路由,如果没有匹配上,则不执行。
-
- id: payment_routh2 uri: lb://cloud-payment-service #匹配提供服务的路由地址 predicates: - Path=/payment/lb/** - After=2020-12-15T20:09:16.589+08:00[Asia/Shanghai] - Cookie=username,zzyy
-
curl命令:打开cmd,输入命令: curl http://localhost:9527/payment/lb 失败 curl http://localhost:9527/payment/lb --cookie "username=zzyy" 成功
-
-
header route predicate
-
- id: payment_routh2 uri: lb://cloud-payment-service #匹配提供服务的路由地址 predicates: - Path=/payment/lb/** - After=2020-12-15T20:09:16.589+08:00[Asia/Shanghai] #- Cookie=username,zzyy - Header=X-Request-Id, \d+ # 请求头要有X-Request-Id属性,并且值为整数的正则表达式
-
测试
curl http://localhost:9527/payment/lb -H "X-Request-Id:1234"
-
-
host route predicate
-
- id: payment_routh2 uri: lb://cloud-payment-service #匹配提供服务的路由地址 predicates: - Path=/payment/lb/** - After=2020-12-15T20:09:16.589+08:00[Asia/Shanghai] #- Cookie=username,zzyy #- Header=X-Request-Id, \d+ # 请求头要有X-Request-Id属性,并且值为整数的正则表达式 - Host=**.atguigu.com
-
测试
curl http://localhost:9527/payment/lb -H "Host: www.atguigu.com"
-
-
method route predicate
-
- id: payment_routh2 uri: lb://cloud-payment-service #匹配提供服务的路由地址 predicates: - Path=/payment/lb/** - After=2020-12-15T20:09:16.589+08:00[Asia/Shanghai] #- Cookie=username,zzyy #- Header=X-Request-Id, \d+ # 请求头要有X-Request-Id属性,并且值为整数的正则表达式 #- Host=**.atguigu.com - Method=GET # Get方法
-
测试
-
-
path route predicate
-
query route predicate
-
- id: payment_routh2 uri: lb://cloud-payment-service #匹配提供服务的路由地址 predicates: - Path=/payment/lb/** - After=2020-12-15T20:09:16.589+08:00[Asia/Shanghai] #- Cookie=username,zzyy #- Header=X-Request-Id, \d+ # 请求头要有X-Request-Id属性,并且值为整数的正则表达式 #- Host=**.atguigu.com #- Method=GET - Query=username, \d+ #要有参数名username,并且还要是整数才能路由
-
测试
curl http://localhost:9527/payment/lb?username=31
-
过滤器(Filter)
-
路由过滤器可以用于修改进入的HTTP请求和返回的HTTP响应,路由过滤器只能指定路由进行使用。spring cloud gateway内置了多种路由过滤器,他们都由GatewayFilter工厂类来生产。
-
spring cloud gateway的Filter的生命周期,包括pre和post。而Filter的种类包括GatewayFilter(四十多种)和GlobalFilter(十多种)。
-
其具体配置,也是在yml文件种进行配置,例如:
- id: payment_routh2 uri: lb://cloud-payment-service #匹配提供服务的路由地址 filters: - AddRequestParameter=X-Request-Id,1024 #过滤器工厂会在匹配的请求头上,添加一堆请求头,名称为X-Request,值为1024 predicates: - Path=/payment/lb/** - After=2020-12-15T20:09:16.589+08:00[Asia/Shanghai]
-
自定义全局GlobalFilter(主要功能是全局日志记录、统一网关鉴权)
-
自定义全局GlobalFilter,主要是实现GlobalFilter接口和Ordered接口。
-
具体步骤:
-
创建filter包,在包下创建MyLogGateFilter类,添加如下代码:
@Component @Slf4j public class MyLogGateWayFilter implements GlobalFilter, Ordered { @Override public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {//Mono 类似Spring种的ModelAndView 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);//去下一个Filter过滤链过滤和验证。 } @Override public int getOrder() { return 0;//加载过滤器的顺序,一般越小,有优先级更高。 } }
-
测试,访问地址:
localhost:9527/payment/lb?uname=z3erer
-
-
需熟练掌握
知识点
- Spring Cloud Gateway的特性。
- 基于Spring Framework 5,Project Reactor和Spring Boot 2.0进行构建;
- 动态路由:能够匹配任何请求属性;
- 可以对路由指定Predicate(断言)和Filter(过滤器);
- 集成Hystrix的断路器功能;
- 集成Spring Cloud服务发现功能;
- 易于编写的Predicate(断言)和Filter;
- 请求限流功能;
- 支持路径重写;
- Zuul1.x模型的不足之处?
- servlet是一个简单的网络IO模型,即Connection per thread。当请求进入servlet container时,servlet container就会为其绑定一个线程,在并发不高的场景下,这种模型是使用的。但是高并发场景下,线程资源代价昂贵(上下文切换,内存消耗大),严重影响请求的处理时间,在一些简单的业务场景下,不希望为每一个request分配一个线程,只要1个或几个线程就能应对极大并发请求。因此,Zuul1.x是一个基于servlet之上的阻塞式处理模型。
- WebFlux是什么,大致描述。
- 传统的Web框架,比如springmvc等,都是基于Servlet API与Servlet容器基础之上运行的。
- 但是,在Servlet3.1之后,有了异步非阻塞的支持。而WebFlux是一个典型非阻塞异步框架,其和兴是基于Reactor的相关API实现的。相对于传统web框架来说,它可以运行在如Netty,Undertow及支持Servlet3.1的容器上。非阻塞式+函数式编程。Spring WebFlux是Spring 5.0引入的新的响应式框架,区别于springmvc,它不需要依赖ServletAPI,它是完全异步非阻塞的,且基于Reactor来实现响应式流规范。
tips
-
一些基本概念:
- Route(路由):路由是构建网关的基本模块,它由ID,目标URI,一些列的断言和过滤器组成,如果断言为true,则匹配该路由。要符合路由的匹配规则,才能被网关进行转发。
- Predicate(断言):参考Java8的java.util.function.Predicate。开发人员可以匹配HTTP请求中的所有内容(例如请求头或请求参数),如果请求与断言相匹配,则进行路由。
- Filter(过滤):指的是Spring框架中GatewayFilter的实例,使用过滤器,可以在亲求被路由前或者之后对请求进行修改。
- =================================================================================================
- web 请求,通过一些匹配条件,定位到真正的服务节点。并在这个转发过程前后,进行一些精细化控制。predicate就是我们的匹配条件;而filter,可以理解为一个无所不能的拦截器。有了这两个元素,再加上uri,就可以实现一个具体的路由了。
-
Spring Cloud Gateway将路由匹配作为Spring WebFlux HandlerMapping基础架构的一部分。spring cloud gateway 包括了许多内置的Route Predicate工厂,所有这些Predicate都与HTTP请求的不同属性相匹配,多个Route Predicate工厂可以进行组合。
-
spring cloud gateway创建route对象时,使用RoutePredicateFactory创建Predicate对象,Predicate对象可以赋值给Route。Spring cloud gateway包含许多内置的route predicate factories。所有这些谓词都匹配HTTP请求的不同属性,多种谓词工厂可以组合,并通过逻辑and。
-
可以给浏览器发送请求的几个方法:
-
jmeter;
-
postman;
-
curl命令:打开cmd,输入命令:
-
curl http://localhost:9527/payment/lb
-
curl http://localhost:9527/payment/lb --cookie "username=zzyy"
代码地址:https://github.com/AJ-Spade/cloud2020/tree/master
-
-