第二十节--GateWay服务网关
Gatway现在已替换zuul
是什么?
Spring cloud gateway是spring官方基于Spring 5.0、Spring Boot2.0和Project Reactor等技术开发的网关,Spring Cloud Gateway旨在为微服务架构提供简单、有效和统一的API路由管理方式,Spring Cloud Gateway作为Spring Cloud生态系统中的网关,目标是替代Netflix Zuul,其不仅提供统一的路由方式,并且还基于Filer链的方式提供了网关基本的功能,例如:安全、监控/埋点、限流等
能干嘛?
反向代理,流量监控,熔断,日志监控,鉴权等
Gateway的特性:
动态路由:能够匹配任何请求属性,
可以对路由指定predicate(断言)和Filter(过滤器)
集成spring cloud服务发现功能
易于编写的predicate(断言)和Filter(过滤器)
请求限流功能
支持路径重写
Gateway三大核心概念
Route(路由):构建网关的基本模块,它有ID,目标URI,一系列的断言和过滤器组成,如果断言为true则匹配该路由
Predicate(断言):参考的是java8的java.util.function.Predicate,开发人员可以匹配HTTP请求中的所有内容(例如请求头或请求参数),如果请求与断言相匹配则进行路由
Filter(过滤):指spring框架中GatewayFilter的实例,使用过滤器,可以在请求被路由或者之后对请求进行修改。
使用的提供者是cloud-provider-payment8001,路由的使用开始
第一步:新建工程cloud-gateway-gateway9527,pom.xml文件
<dependencies> <!--gateway--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-gateway</artifactId> </dependency> <!-- 将微服务provider注册进eureka:引入eureka客户端 --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency> <dependency> <groupId>com.hx.springcloud</groupId> <artifactId>cloud-api-commos</artifactId> <version>1.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </dependency> <!--热部署 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <scope>runtime</scope> <optional>true</optional> </dependency> </dependencies>
第二步:yml文件
server:
port: 9527
spring:
application:
name: cloud-gateway
cloud:
gateway:
routes:
- id: payment-routh #路由的ID 没有固定规则但要求唯一 建议配合服务名
uri: http://localhost:8001 #匹配后提供的路由地址
predicates:
- Path=/admin/findPaymentById/** #断言 路径相匹配的进行路由
- id: payment-routh2 #路由的ID 没有固定规则但要求唯一 建议配合服务名
uri: http://localhost:8001 #匹配后提供的路由地址
predicates:
- Path=/admin/findPaymentList/** #断言 路径相匹配的进行路由
eureka:
instance:
instance-id: cloud-gateway9527 #改变客户端在服务端显示的名称
prefer-ip-address: true #访问路径显示IP地址
client: #讲客户端注册到服务器
service-url:
#defaultZone: http://eureka7001:7001/eureka/,http://eureka7002:7002/eureka/,http://eureka7003:7003/eureka/
defaultZone: http://eureka7001:7001/eureka/,http://eureka7002:7002/eureka/
第三步:主启动类
@EnableEurekaClient @SpringBootApplication public class Gateway9527 { public static void main(String[] args) { SpringApplication.run(Gateway9527.class,args); } }
第四步:启动eureka,gateway9527,cloud-provider-payment8001
1 .使用8001访问
2 .使用9527访问
目的主要是为了保护8001端口,访问提供者时不使用8001暴露,根据网关过滤从而保护
gateway配置有两种方法
第一种:yml配置
cloud: gateway: routes: - id: payment-routh #路由的ID 没有固定规则但要求唯一 建议配合服务名 uri: http://localhost:8001 #匹配后提供的路由地址 predicates: - Path=/admin/findPaymentById/** #断言 路径相匹配的进行路由 - id: payment-routh2 #路由的ID 没有固定规则但要求唯一 建议配合服务名 uri: http://localhost:8001 #匹配后提供的路由地址 predicates: - Path=/admin/findPaymentList/** #断言 路径相匹配的进行路由
第二种:直接写java代码配置,自己写一个
业务需求:通过9527网关访问到外网的百度新闻网址
1 .别写一个配置类GatewayConfig
@Configuration public class GatewayConfig { /** * 发送localhost:9527/guonei 请求时,将会转发到国内百度官网 */ @Bean public RouteLocator customRouteLocator(RouteLocatorBuilder routeLocatorBuilder){ RouteLocatorBuilder.Builder routes = routeLocatorBuilder.routes(); routes.route("path_route_hx", r->r.path("/guonei") .uri("http://news.baidu.com/guonei")).build(); routes.route("path_route_hx1", r->r.path("/guoji")//跳到国际 .uri("http://news.baidu.com/guoji")).build(); return routes.build(); } }
当前存在的问题? 一个端口就需要写一个id与之对应,如果存在N个端口,就不好维护,如何改进
- id: payment-routh #路由的ID 没有固定规则但要求唯一 建议配合服务名
uri: http://localhost:8001 #匹配后提供的路由地址
predicates:
- Path=/admin/findPaymentById/** #断言 路径相匹配的进行路由
只需要修改和添加以下即可
spring: application: name: cloud-gateway cloud: gateway: discovery: locator: enabled: true routes: - id: payment-routh #路由的ID 没有固定规则但要求唯一 建议配合服务名 # uri: http://localhost:8001 #匹配后提供的路由地址 uri: lb://cloud-payment-service #匹配之后提供服务的路由地址 predicates: #- Path=/admin/findPaymentById/** #断言 路径相匹配的进行路由 - Path=/admin/** #访问包含admin的config目前被Nacos替代所有路径 - id: payment-routh2 #路由的ID 没有固定规则但要求唯一 建议配合服务名 #uri: http://localhost:8001 #匹配后提供的路由地址 uri: lb://cloud-payment-service #匹配之后提供服务的路由地址 predicates: - Path=/admin/findPaymentList/** #断言 路径相匹配的进行路由
Predicate的使用开始
predicates: 断言其实也就是验证地址是否通过,比如 - Path=/admin/**地址中没有带有admin的就不会让它通过
#- Path=/admin/findPaymentById/** #断言 路径相匹配的进行路由
- Path=/admin/** #访问包含admin的所有路径
Path:只是其中一个属性
predicate其它的基本属性请参照: https://www.wanglibing.com/2019/09/01/Spring-Cloud-Gateway%E5%9F%BA%E7%A1%80/
Gateway的Filter
是什么?
路由过滤器可用于修改进入的HTTP请求和返回的HTTP响应,路由过滤器只能指定路由进行使用
简介
网关经常需要对路由请求进行过滤,进行一些操作,如鉴权之后构造头部之类的,过滤的种类很多,如增加请求头、增加请求 参数 、增加响应头和断路器等等功能,这就用到了Spring Cloud Gateway 的 Filter。
作用
当我们有很多个服务时,比如下图中的user-service、goods-service、sales-service等服务,客户端请求各个服务的Api时,每个服务都需要做相同的事情,比如鉴权、限流、日志输出等。
对于这样重复的工作,可以在微服务的上一层加一个全局的权限控制、限流、日志输出的Api Gateway服务,然后再将请求转发到具体的业务服务层。这个Api Gateway服务就是起到一个服务边界的作用,外界的请求访问系统,必须先通过网关层。
生命周期
Spring Cloud Gateway 的 Filter 的生命周期不像 Zuul 的那么丰富,它只有两个:“pre” 和 “post”。
-
PRE: 这种过滤器在请求被路由之前调用。我们可利用这种过滤器实现身份验证、在集群中选择请求的微服务、记录调试信息等。
-
POST:这种过滤器在路由到微服务以后执行。这种过滤器可用来为响应添加标准的 HTTP Header、收集统计信息和指标、将响应从微服务发送给客户端等。
分类
Spring Cloud Gateway 的 Filter 从作用范围可分为另外两种GatewayFilter 与 GlobalFilter。
-
GatewayFilter:应用到单个路由或者一个分组的路由上。
-
GlobalFilter:应用到所有的路由上。
Gateway filter
过滤器允许以某种方式修改传入的HTTP请求或传出的HTTP响应。过滤器的作用域为特定路由。Spring Cloud Gateway包含许多内置的GatewayFilter工厂。
第一步:cloud-gateway-gateway9527工程中,写一个MyGatewayFilter类,只需要实现两个接口implements GlobalFilter,Ordered
@Component @Slf4j public class MyGatewayFilter implements GlobalFilter,Ordered { /** * 如果带有id的这个参数并且参数值大于0则通过,否则不通过 */ @Override public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { log.info("gateway拦截器执行开始"); String id=exchange.getRequest().getQueryParams().getFirst("id"); if(Integer.parseInt(id)<0){ log.info("输入的参数非法,请重新输入"); exchange.getResponse().setStatusCode(HttpStatus.NOT_ACCEPTABLE); return exchange.getResponse().setComplete(); } return chain.filter(exchange); } @Override public int getOrder() { return 0; } }
第二步:启动eureka,8001,9527工程测试
带参数小于0时
带参数大于0时