文章目录提示:本文主要对GateWay新一代服务网关进行总结
- 前言
- 一、概述
- 1、简介
- 2、三大核心概念
- 3、GateWay工作流程
- 二、入门配置
- 1、pom.xml
- 2、application.yml
- 3、主启动类
- 3.1 9527主启动类
- 3.2 cloud-provider-payment8001 主启动类修改
- 4、业务类
- 5、9527网关做路由映射
- 6、9527application.yml新增网关配置
- 7、测试
- 8、配置说明
- 9、通过微服务名实现动态路由
- 9.1 启动
- 9.2 cloud-gateway-gateway9527 yml修改
- 9.3 测试
- 三、Predicate的使用
- 1、Predicate是什么
- 2、常用的Route Predicate
- 2.1 After Route Predicate
- 2.2 Before Route Predicate
- 2.3 Between Route Predicate
- 2.4 Cookie Route Predicate
- 2.5 Header Route Predicate
- 2.6 Host Route Predicate
- 2.7 Method Route Predicate
- 2.8 Path Route Predicate
- 2.9 Query Route Predicate
- 2.10 小总结
- 四、Filter的使用
- 1、Filter是什么
- 2、SpringCloud GateWay的Filter
- 2.1 常用的GateWayFilter
- 3、自定义全局过滤器(GlobalFilter)
- 3.1 俩个主要接口介绍
- 3.2 能干嘛
- 3.3 案例
- 3.4 测试
前言
提示:这里可以添加本文要记录的大概内容:
本文主要对GateWay新一代服务网关进行总结
提示:以下是本篇文章正文内容
一、概述 1、简介是什么:Cloud全家桶中有个很重要的组件就是网关,在1.x版本中都是采用Zuul网关。但在2.x版本中,zuul升级一直跳票,SpringCloud最后自己研发了一个网关替代zuul,就是Spring Cloud GateWay。
GateWay是在spring生态系统之上构建的API服务网关,基于spring5,Spring Boot2和Project Reactor技术。GateWay旨在提供一种简单而有效的方式来对API进行路由,以及提供一些强大的过滤器功能,例如:熔断、限流、重试等。GateWay 基于WebFlux框架实现,而WebFlux框架底层则使用了高性能的Reactor模式通信框架Netty。
Spring Cloud GateWay的目标是提供统一的路由方式且基于Filter链的方式提供网关的基本功能,例如:安全、监控/指标、限流。
一句话:Spring Cloud GateWay使用WebFlux中的Reactor-netty响应式编程组件,底层使用了netty通讯框架。
能干嘛:反向代理、鉴权、流量控制、熔断、日志监控…
微服务架构中网关的位置:
Spring Cloud GateWay 具有如下特性:
基于Spring5、Project Reactor和SpringBoot2.0进行构建;
动态路由:能够匹配任何请求属性;
可以对路由指定Predicate(断言)和Filter(过滤器);
集成Hystrix的断路器功能;
集成SpringCloud服务发现功能;
易于编写Predicate(断言)和Filter(过滤器);
请求限流功能;
支持路径重写;
Route(路由): 路由是构建网关的基本模块,它由ID,目标URI,一些列的断言和过滤器组成,如果断言为true则匹配该路由。
Predicate(断言): 参考的是java8的java.util.function.Predicate,开发人员可以匹配HTTP请求中的内容(例如请求头和请求参数),如果请求与断言相匹配则进行路由。
Filter(过滤): 指的是Spring框架中GateWayFilter的实例,使用过滤器,可以在请求被路由前或者之后对请求进行修改。
总体:web请求,通过一些匹配条件,定位到真正的服务节点,并在这个转发过程前后,进行一些精细化控制。predicate就是我们的匹配条件;而Filter,就可以理解为一个无所不能的拦截器。有了这两个元素,再加上目标uri,就可以实现一个具体的路由
3、GateWay工作流程
客户端向Spring Cloud GateWay发出请求,然后在GateWay Handler Mapping中找到与请求相匹配的路由,将其发送到GateWay Web Handler。Handler再通过指定的过滤器链来将请求发送到我们实际的服务执行业务逻辑,然后返回。过滤器使用虚线分开是因为过滤器可能会在发送代理请求之前(“pre”)或之后(“post”)执行业务逻辑。
Filter在"pre"类型的过滤器可以做参数校验,权限校验,流量监控,日志输出,协议转换等。在"post"类型的过滤器中可以做响应内容、响应头的修改,日志的输出,流量监控等有着非常重要的作用。
二、入门配置新建Module
新建cloud-gateway-gateway9527
网关作为服务也需要注册到注册中心
2、application.ymlcloud2022 com.atguidu.springcloud 1.0-SNAPSHOT 4.0.0 cloud-gateway-gateway9527 com.atguidu.springcloud cloud-api-commons ${project.version} org.springframework.cloud spring-cloud-starter-gateway org.springframework.cloud spring-cloud-starter-netflix-eureka-client org.springframework.boot spring-boot-devtools runtime true org.projectlombok lombok true org.springframework.boot spring-boot-starter-test
server:
port: 9527
spring:
application:
name: cloud-gateway
eureka:
client:
register-with-eureka: true #表示将自己注册进Eureka Server
fetch-registry: true #表示是否从EurekaServer抓取已有的注册信息,默认为true。单节点无所谓,集群必须设置为true才能配合ribbon使用负载均衡
service-url:
#defaultZone: http://localhost:7001/eureka #单机版
defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka #集群版
3、主启动类
3.1 9527主启动类
package com.atguigu.springcloud;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
@SpringBootApplication
@EnableEurekaClient
public class GateWayMain9527 {
public static void main(String[] args) {
SpringApplication.run(GateWayMain9527.class, args);
}
}
3.2 cloud-provider-payment8001 主启动类修改
package com.atguigu.springcloud;
import com.netflix.hystrix.contrib.metrics.eventstream.HystrixMetricsStreamServlet;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.context.annotation.Bean;
@SpringBootApplication
@EnableEurekaClient
@EnableDiscoveryClient //服务发现
public class PaymentMain8001 {
public static void main(String[] args) {
SpringApplication.run(PaymentMain8001.class,args);
}
@Bean
public ServletRegistrationBean getServlet() {
HystrixMetricsStreamServlet streamServlet = new HystrixMetricsStreamServlet();
ServletRegistrationBean registrationBean = new ServletRegistrationBean(streamServlet);
registrationBean.setLoadOnStartup(1);
registrationBean.addUrlMappings("/hystrix.stream");
registrationBean.setName("HystrixMetricsStreamServlet");
return registrationBean;
}
}
4、业务类
无
5、9527网关做路由映射cloud-provider-payment8001看看controller的访问地址
配置:
/payment/get/{id}
/payment/lb
我们目前不想暴露8001端口,希望在8001外面套一层9527。
6、9527application.yml新增网关配置application.yml:
server:
port: 9527
spring:
application:
name: cloud-gateway
cloud:
gateway:
routes:
- id: payment_routh #路由id,没有固定规则但要求唯一,建议配合服务名
uri: http://localhost:8001 #匹配提供服务的路由地址
predicates:
- Path=/payment/get
routes.route("path_route_atguiggu",
r -> r.path("/guonei")
.uri("http://news.baidu.com/guonei"));
return routes.build();
}
@Bean
public RouteLocator customRouteLocatoor2(RouteLocatorBuilder routeLocatorBuilder) {
RouteLocatorBuilder.Builder routes = routeLocatorBuilder.routes();
routes.route("path_route_atguiggu2",
r -> r.path("/guoji")
.uri("http://news.baidu.com/guoji"));
return routes.build();
}
}
9、通过微服务名实现动态路由
默认情况下GateWay会根据注册中心的服务列表,以注册中心上微服务名为路径创建动态路由进行转发,从而实现动态路由的功能。
9.1 启动eureka7001/7002 + 两个服务提供者8001/8002
9.2 cloud-gateway-gateway9527 yml修改server:
port: 9527
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=/payment/get/** #断言,路径相匹配的进行路由
- id: payment_routh2
#uri: http://localhost:8001
uri: lb://cloud-payment-service #匹配后提供服务的路由地址
predicates:
- Path=/payment/lb/**
eureka:
client:
register-with-eureka: true #表示将自己注册进Eureka Server
fetch-registry: true #表示是否从EurekaServer抓取已有的注册信息,默认为true。单节点无所谓,集群必须设置为true才能配合ribbon使用负载均衡
service-url:
#defaultZone: http://localhost:7001/eureka #单机版
defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka #集群版
需要注意的是uri的协议lb,表示启用GateWay的负载均衡功能。
lb://serviceName 是spring cloud gateway在微服务中自动为我们创建的负载均衡uri。
访问: http://localhost:9527/payment/lb
结果:
8001、8002交替提供服务。
启动我们的gateway9527
Route Predicate Factories是什么东东?
SpringCloud GateWay 将路由匹配作为Spring WebFlux HandlerMapping基础架构的一部分。SpringCloud GateWay包括许多内置的Route Predicate工厂。所有这些Predicate都与HTTP请求的不同属性匹配。多个Route Predicate工厂可以进行组合。
Spring Cloud GateWay创建Route对象时,使用RoutePredicateFactory创建Predicate对象,Predicate对象可以赋值给Route。
2、常用的Route Predicate 2.1 After Route Predicate在yml文件中添加:- After=2021-12-03T23:22:29.162+08:00[Asia/Shanghai],设置在这个时间之后才匹配
server:
port: 9527
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=/payment/get/** #断言,路径相匹配的进行路由
- id: payment_routh2
#uri: http://localhost:8001
uri: lb://cloud-payment-service #匹配后提供服务的路由地址
predicates:
- Path=/payment/lb/**
- After=2021-12-03T23:22:29.162+08:00[Asia/Shanghai]
eureka:
client:
register-with-eureka: true #表示将自己注册进Eureka Server
fetch-registry: true #表示是否从EurekaServer抓取已有的注册信息,默认为true。单节点无所谓,集群必须设置为true才能配合ribbon使用负载均衡
service-url:
#defaultZone: http://localhost:7001/eureka #单机版
defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka #集群版
当前时间不满足条件时:
在什么时间之前才匹配
- Before=2021-12-03T23:22:29.162+08:00[Asia/Shanghai]
在什么时间之间才匹配
- Between=- After=2021-12-03T23:22:29.162+08:00[Asia/Shanghai],- After=2021-12-04T23:22:29.162+08:00[Asia/Shanghai]
Cookie Route Predicate需要两个参数,一个是Cookie Name,一个是正则表达式。路由规则会通过获取对应的Cookie name和正则表达式进行匹配,如果匹配上就执行路由,如果没有匹配上则不执行。
添加:- Cookie=username,zzyy
server:
port: 9527
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=/payment/get/** #断言,路径相匹配的进行路由
- id: payment_routh2
#uri: http://localhost:8001
uri: lb://cloud-payment-service #匹配后提供服务的路由地址
predicates:
- Path=/payment/lb/**
#- After=2021-12-03T23:22:29.162+08:00[Asia/Shanghai]
#- Before=2021-12-04T23:22:29.162+08:00[Asia/Shanghai]
#- Between=2021-12-03T23:22:29.162+08:00[Asia/Shanghai],2021-12-04T23:22:29.162+08:00[Asia/Shanghai]
- Cookie=username,zzyy
eureka:
client:
register-with-eureka: true #表示将自己注册进Eureka Server
fetch-registry: true #表示是否从EurekaServer抓取已有的注册信息,默认为true。单节点无所谓,集群必须设置为true才能配合ribbon使用负载均衡
service-url:
#defaultZone: http://localhost:7001/eureka #单机版
defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka #集群版
1.不带cookies访问
2.带上cookies访问
两个参数:一个是属性名称,一个是正则表达式,这个属性值和正则表达式匹配则执行路由
在9527 yml文件中,predicates中添加:- Header=X-Request-Id,d+ #请求头要有X-Request-Id属性并且值为整数
测试:
请求头中没有该属性时:
Host Route Predicate接收一组参数,一组匹配的域名列表,这个模板是一个ant分隔的模板,用.号作为分隔符
例:- Host=**.atguigu.com #什么样的URL路径过来
例:- Method=GET #什么样的请求方法:
2.8 Path Route Predicate请求的路径要匹配才路由,例:- Path=/payment/lb/**
2.9 Query Route Predicate带有什么参数的,例:- Query=username,d+ #要参数名username并且值为整数
9527 yml配置:
server:
port: 9527
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=/payment/get/** #断言,路径相匹配的进行路由
- id: payment_routh2
#uri: http://localhost:8001
uri: lb://cloud-payment-service #匹配后提供服务的路由地址
predicates:
- Path=/payment/lb/**
#- After=2021-12-03T23:22:29.162+08:00[Asia/Shanghai]
#- Before=2021-12-04T23:22:29.162+08:00[Asia/Shanghai]
#- Between=2021-12-03T23:22:29.162+08:00[Asia/Shanghai],2021-12-04T23:22:29.162+08:00[Asia/Shanghai]
#- Cookie=username,zzyy
#- Header=X-Request-Id,d+ #请求头要有X-Request-Id属性并且值为整数
#- Host=**.atguigu.com #什么样的URL路径过来
#- Method=GET #什么样的请求方法
#- Query=username,d+ #要参数名username并且值为整数
eureka:
client:
register-with-eureka: true #表示将自己注册进Eureka Server
fetch-registry: true #表示是否从EurekaServer抓取已有的注册信息,默认为true。单节点无所谓,集群必须设置为true才能配合ribbon使用负载均衡
service-url:
#defaultZone: http://localhost:7001/eureka #单机版
defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka #集群版
说白了,Predicate就是为了实现一组匹配规则,让请求过来找到对应的Route进行处理。
四、Filter的使用 1、Filter是什么
路由过滤器可用于修改进入的HTTP请求和返回的HTTP响应,路由过滤器只能指定路由进行使用。Spring Cloud GateWay内置了多种路由过滤器,他们都由GateWayFilter的工厂类来产生。
生命周期:pre(业务逻辑之前),post(业务逻辑之后)
种类:GateWayFilter(单一的),GlobalFilter(全局的)
AddRequestParameter:
在9527的yml中添加filter
server:
port: 9527
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=/payment/get/** #断言,路径相匹配的进行路由
- id: payment_routh2
#uri: http://localhost:8001
uri: lb://cloud-payment-service #匹配后提供服务的路由地址
predicates:
- Path=/payment/lb/**
#- After=2021-12-03T23:22:29.162+08:00[Asia/Shanghai]
#- Before=2021-12-04T23:22:29.162+08:00[Asia/Shanghai]
#- Between=2021-12-03T23:22:29.162+08:00[Asia/Shanghai],2021-12-04T23:22:29.162+08:00[Asia/Shanghai]
#- Cookie=username,zzyy
#- Header=X-Request-Id,d+ #请求头要有X-Request-Id属性并且值为整数
#- Host=**.atguigu.com #什么样的URL路径过来
#- Method=GET #什么样的请求方法
#- Query=username,d+ #要参数名username并且值为整数
filters:
- AddRequestParameter=X-Request-Id,1024 #过滤器工厂会在匹配的请求头上加一对请求头,名称为X-Request-Id值为1024
eureka:
client:
register-with-eureka: true #表示将自己注册进Eureka Server
fetch-registry: true #表示是否从EurekaServer抓取已有的注册信息,默认为true。单节点无所谓,集群必须设置为true才能配合ribbon使用负载均衡
service-url:
#defaultZone: http://localhost:7001/eureka #单机版
defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka #集群版
3、自定义全局过滤器(GlobalFilter)
3.1 俩个主要接口介绍
implements GlobalFilter,Ordered
3.2 能干嘛全局日志记录、统一网关鉴权…
3.3 案例package com.atguigu.springcloud.filter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
import java.util.Date;
@Component
@Slf4j
public class MyLogGateWayFilter implements GlobalFilter, Ordered {
@Override
public Mono 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
public int getOrder() {
return 0;//加载过滤器的顺序,数字越小,优先级越高
}
}
3.4 测试
7.3.3 代码完成后,直接启动服务7001、7002、8001、8002、9527
测试正确地址:http://localhost:9527/payment/lb?uname=23
不满足过滤条件的地址:



