失眠网,内容丰富有趣,生活中的好帮手!
失眠网 > 微服务学习之Gateway服务网关【Hoxton.SR1版】

微服务学习之Gateway服务网关【Hoxton.SR1版】

时间:2018-09-16 23:30:39

相关推荐

微服务学习之Gateway服务网关【Hoxton.SR1版】

目录

1 Gateway是什么

2 能干嘛

3 Gateway特性

4 Gateway与Zuul的区别

5 Gateway三大核心概念

5.1 路由Route

5.2 断言Predicate

5.3 过滤器(Filter)

5.4 Gateway工作流程

6 Gateway代码实操

6.1 基本环境搭建

6.1.1 pom依赖

6.1.2application.yml(yml配置方式配置路由)

6.1.3 主启动类

6.1.4 服务提供者

6.2 Gateway测试

6.2.1 yml方式配置路由测试

6.2.2代码中注入RouteLocator的Bean的方式配置路由测试

6.2.3 动态路由配置

6.2.4 断言Predicate

6.2.5 Route Filter路由过滤器

7 总结

1 Gateway是什么

Gateway是一个在Spring生态系统之上构建的API网关,包括:Spring 5,Spring Boot 2和Project Reactor。Spring Cloud Gateway旨在提供一种简单而有效的方法来路由到API,并为它们提供跨领域的关注点,例如:安全性,监视/指标和弹性。(官网介绍)

SpringCloud全家桶中有一个很重要的组件就是网关,在1.x版本中都是采用的Zuul网关,但在2.x版本中,Netflix对Zuul的升级工作一直跳票,最终SpringCloud自己研发了Gateway用来替代Zuul。Netflix很多组件(Eureka、Hystrix等)都进入维护阶段,选择Gateway做网关是更有保障的,毕竟是SpringCloud团队自己开发的。

SpringCloud Gateway作为SpringCloud生态系统中的网关,目标是替代Zuul。在SpringCloud2.0以上版本中,没有对新版本的Zuul2.0最新高性能版本进行集成,仍然还是使用zuul1.x非Reactor模式的老版本。为了提升网关的性能,SpringCloud Gateway是基于WebFlex框架实现的,而WebFlex框架底层使用了Reactor模式通信框架Netty。

官网Gateway的工作原理图:

2 能干嘛

反向代理、鉴权、流量控制、熔断、日志监控等等。

微服务中网关处于什么位置?

3 Gateway特性

1 ),基于Spring 5,Spring Boot 2和Project Reactor进行构建。

2),动态路由能够匹配任何请求属性。

3),可以对路由指定Predicate(断言)和Filter(过滤),易于编写Predicate和Filter。

4),集成Hystrix的断路器功能。

5),集成SpringCloud的服务发现功能。

6),请求限流功能。

7),支持路径重写。

4 Gateway与Zuul的区别

5 Gateway三大核心概念

5.1 路由Route

路由是构建网关的基本模块,它由ID、目标URL、一系列的断言、过滤器组成,如果断言为true,那么匹配该路由。

5.2 断言Predicate

参考Java 8 Function Predicate,开发人员可以匹配Http请求中的所有内容(例如请求头、请求参数),如果请求与断言相匹配则进行路由。

5.3 过滤器(Filter)

过滤器是Spring框架中GatewayFilter的实例,使用过滤器可以实现在请求被路由前或者之后对请求进行修改。

5.4 Gateway工作流程

路由转发+执行过滤器链。

6 Gateway代码实操

Gateway网关路由有两种配置方式:yml文件配置、代码中注入RouteLocator的Bean。

6.1 基本环境搭建

6.1.1 pom依赖

在父工程下新建一个名为cloud-gateway-gateway9527的module,对应的pom依赖如下:

<?xml version="1.0" encoding="UTF-8"?><project xmlns="/POM/4.0.0"xmlns:xsi="/2001/XMLSchema-instance"xsi:schemaLocation="/POM/4.0.0 /xsd/maven-4.0.0.xsd"><parent><artifactId>cloud</artifactId><groupId>com.bighuan.springcloud</groupId><version>1.0-SNAPSHOT</version></parent><modelVersion>4.0.0</modelVersion><artifactId>cloud-gateway-gateway9527</artifactId><dependencies><!--gateway--><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-gateway</artifactId></dependency><!-- Eureka client--><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-eureka-client</artifactId></dependency><!--引入自定义的api通用包,可以使用Payment支付Entity--><dependency><groupId>com.bighuan.springcloud</groupId><artifactId>cloud-api-commons</artifactId><version>${project.version}</version></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><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId><configuration><mainClass>com.bighuan.springcloud.GatewayMain9527</mainClass></configuration><executions><execution><goals><goal>repackage</goal></goals></execution></executions></plugin></plugins></build></project>

6.1.2application.yml(yml配置方式配置路由)

application.yml文件配置如下。关于路由配置可以参考官网:id表示路由的ID,没有固定的规则,但是一定要唯一,可以配合服务名来配置;uri表示匹配后提供服务的路由地址;predicates下的Path是为了匹配对应的路径。

关于注册中心的相关配置,都在此前的博客中有相关记录,不再赘述。

server:port: 9527spring:application:name: cloud-gatewaycloud:gateway:routes:- id: payment_routh# payment_route 路由的ID,没有固定规则但要求唯一,建议配合服务名uri: http://127.0.0.1:8001 # 匹配后提供服务的路由地址predicates:- Path=/payment/get/** # 断言,路径相匹配的进行断言- id: payment_routh2# 路由的ID,没有固定规则但要求唯一,建议配合服务名uri: http://127.0.0.1:8001 # 匹配后提供服务的路由地址predicates:- Path=/payment/lb/** # 断言,路径相匹配的进行断言eureka:instance:hostname: cloud-gateway-serviceclient: # 服务提供者的provider注册进eureka的服务列表里register-with-eureka: truefetch-registry: trueservice-url:defaultZone: http://localhost:7001/eureka

6.1.3 主启动类

主启动类并没有特殊的配置,比较简单。

@SpringBootApplication@EnableEurekaClientpublic class GatewayMain9527 {public static void main(String[] args) {SpringApplication.run(GatewayMain9527.class,args);}}

6.1.4 服务提供者

在yml文件中关于路由的配置那一块,uri和predicates下的Path等配置都是为了指向服务提供者。服务提供者相关的博客可参考此前的博客,为行文方便,只粘贴出对应的controller。

@GetMapping(value = "/payment/lb")public String getPaymentLB(){return serverPort;}@GetMapping(value = "/payment/get/{id}")public CommonResult<Payment> getPaymentById(@PathVariable("id") Long id) {Payment payment = paymentService.getPaymentById(id);log.info("*****查询结果*****:" + payment+",server.port:"+serverPort);if (payment != null) {return new CommonResult(200, "查询成功,serverPort:"+serverPort, payment);} else {return new CommonResult(444, "没有对应记录,查询ID:"+id+","+"serverPort:"+serverPort, null);}}

6.2 Gateway测试

6.2.1 yml方式配置路由测试

分别启动注册中心Eureka7001、服务提供者8001、Gateway9527,浏览器分别访问:

http://127.0.0.1:9527/payment/get/31、http://127.0.0.1:9527/payment/lb

发现都成功返回了对应的数据,前者需要查询数据库,后者则直接返回服务提供者的端口8001。通过Gateway9527,将服务提供者隐藏起来,对外界是不可见的,通过服务网关的路由就可以访问。

6.2.2代码中注入RouteLocator的Bean的方式配置路由测试

代码配置方式可参考官网的配置,如下:

本文配置类代码如下,特别注意的是,需要让此类可以被主启动类扫描到。

//代码配置: 配置路由的第二种方式@Configurationpublic class GatewayConfig {@Beanpublic RouteLocator routes(RouteLocatorBuilder builder) {RouteLocatorBuilder.Builder routes = builder.routes();return routes.route("path_route_bighuan",r -> r.path("/guonei").uri("/guonei")).build();}}

同样,分别启动注册中心7001、服务提供者8001(只测试代码配置路由,不需要启动也可以)、Gateway9527,访问http://127.0.0.1:9527/guonei,页面跳转到到了国内百度新闻的页面。

6.2.3 动态路由配置

以上的测试中,只有一个服务提供者8001,如果不止一个服务提供者8001,还有服务提供者8002、8003,每个都要在配置文件中配置一次的话,那么是不现实的。动态路由就可以解决这个问题。

默认情况下,Gateway会根据注册中心注册的服务列表,以注册中心上微服务名为路径创建动态路由进行转发,从而实现动态路由的功能。

动态路由的配置文件为,application-dynamic.yml,配置如下:

server:port: 9527spring:application:name: cloud-gatewaycloud:gateway:discovery:locator:enabled: true # 开启从注册中心动态创建路由的功能,利用微服务名进行路由routes:- id: payment_routh# payment_route 路由的ID,没有固定规则但要求唯一,建议配合服务名# uri: http://127.0.0.1:8001 # 匹配后提供服务的路由地址uri: lb://CLOUD-PAYMENT-SERVICE # 匹配后提供服务的路由地址predicates:- Path=/payment/get/** # 断言,路径相匹配的进行断言- id: payment_routh2# 路由的ID,没有固定规则但要求唯一,建议配合服务名# uri: http://127.0.0.1:8001 # 匹配后提供服务的路由地址uri: lb://CLOUD-PAYMENT-SERVICE # 匹配后提供服务的路由地址predicates:- Path=/payment/lb/** # 断言,路径相匹配的进行断言eureka:instance:hostname: cloud-gateway-serviceclient: # 服务提供者的provider注册进eureka的服务列表里register-with-eureka: truefetch-registry: trueservice-url:defaultZone: http://localhost:7001/eureka

说明:

1)spring.cloud.gateway.discovery.locator.enabled设置为true,开启从注册中心动态创建路由的功能,利用微服务名进行路由。

2)uri的协议为lb,表示基于服务注册的负载均衡,即启动Gateway的负载均衡功能,CLOUD-PAYMENT-SERVICE是服务提供者的微服务名。

测试步骤:启动一个注册中心Eureka7001、分别启动服务提供者8001和8002、启动Gateway9527,然后连续访问:http://127.0.0.1:9527/payment/lb,返回结果则为8001、8002交替出现,说明动态路由配置成功,而且负载均衡也实现了。

6.2.4 断言Predicate

SpringCloud Gateway包含许多内置的Route Predicate工厂,所有这些Predicate都与HTTP请求的不同属性相匹配,多个Predicate工厂可以进行组合。可以理解为Predicate就是 Sql语句中Where后的条件,可以有多个条件进行条件限制。

SpringCloud Gateway创建Route对象时,使用RoutePredicateFactory创建Predicate对象,Predicate对象可以赋值给Route对象。官网可以看到,至少内置了11中Route Predicate Factory。其中,第8种Path Route Predicate Factory前文已经接触过了,主要用来匹配路径。

在application-dynamic.yml的payment_routh2的predicates下增加after配置,表示需要在该时间之后才能成功匹配路由匹配。

- After=-03-28T17:25:10.065+08:00[Asia/Shanghai]

这种特殊的时间可以通过ZoneDateTime来获取

ZonedDateTime now = ZonedDateTime.now();// -03-28T16:51:32.977+08:00[Asia/Shanghai]System.out.println(now);

分别启动项目,在设置的after时间之前访问,会报错。

当时间过了after时间之后,就可以正常访问了。

Before、Between Route Predicate Factory的配置方式类似。

还是在application-dynamic.yml的payment_routh2的predicates下增加cookie配置。

- Cookie=username,bighuan

分别启动项目,一开始请求时不带cookie,直接返回404;带上cookie后,访问正常。

6.2.5 Route Filter路由过滤器

路由过滤器允许以某种方式修改传入的HTTP请求或传出的HTTP响应。路由过滤器适用于特定路由。Spring Cloud Gateway包括许多内置的GatewayFilter工厂。Spring Cloud Gateway内置了多种路由过滤器,它们都GatewayFilter工厂类产生。(官网gatewayfilter-factories,配置参考官网即可)

Filter的生命周期有两种:pre、post。

在“pre”类型的过滤器可以做参数校验、权限校验、流量监控、日志输出、协议转换等,在“post”类型的过滤器中可以做响应内容、响应头的修改,日志输出,流量监控等。(注:这段话来自某大佬博客)

Filter的种类有两种:GatewayFilter、GlobalFilter。

自定义全局GlobalFilter过滤器

自定义全局过滤器,需要实现GlobalFilter、Ordered两个接口。自定义全局过滤器,可以实现全局日志记录、统一网关鉴权等等。

@Component@Slf4jpublic class MyLogGateWayFilter implements GlobalFilter,Ordered {@Overridepublic 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("*****用户名为空,是非法用户,o(╥﹏╥)o");exchange.getResponse().setStatusCode(HttpStatus.NOT_ACCEPTABLE);return exchange.getResponse().setComplete();}return chain.filter(exchange);}/*** 加载过滤器的优先级,值越小,优先级越高* @return*/@Overridepublic int getOrder() {return 0;}}

测试:使用application.yml启动Gateway9527,访问http://127.0.0.1:9527/payment/lb?uname=bighuan可以通过获得结果,http://127.0.0.1:9527/payment/lb则会被拦截。

7 总结

虽然写这篇博客花的的时间比较长,但坚持坚持,会有收获的!

如果觉得《微服务学习之Gateway服务网关【Hoxton.SR1版】》对你有帮助,请点赞、收藏,并留下你的观点哦!

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。