介绍:
1、Spring Cloud Gateway基于 Spring Boot 2.x,Spring WebFlux 和 Project Reactor 构建,使用了 Webflux 中的 reactor-netty 响应式编程组件,底层使用了 Netty 通讯框架
2、GateWay网关的主要作用:
【1】路由转发
【2】过滤鉴权
【3】负载均衡(流量控制)
3、GateWay网关的三大概念:
【1】Predicate(断言)
【2】Route(路由)
【3】Filter(过滤)
一、引入nacos和gateway依赖包:
<dependencies>
<!-- gateway -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<!-- nacos客户端 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
注意:不需要引入web依赖,否则启动服务会报错。因为gateway内部集成了Netty服务器
二、路由转发:
1、写法一:
server:
port: 8000
spring:
application:
name: gateway-server
cloud:
# nacos 注册中心
nacos:
discovery:
server-addr: http://localhost:8848
username: nacos
password: nacos
# 动态路由
gateway:
discovery:
locator:
enabled: true # 开启服务发现让gateway可以发现注册中心的服务,解析微服务名称为主机名和端口,实现动态路由
# lowerCaseServiceId: true # 请求服务是小写的时候改成true(默认为false轻微服务必须是大写)
# 路线
routes:
# 账户模块服务
- id: seata-account-service # 路由Id,没有规则限制,但要唯一
# http方式
#uri: http://localhost:7000
# lb方式
uri: lb://seata-account-service # 断言成功后提供的路由地址,lb为负载均衡
predicates:
- Path=/account/** # 断言规则,注意需要和 tomcat servlet容器上下文路径对应
# 订单模块服务
- id: seata-order-service # 路由Id,没有规则限制,但要唯一
uri: lb://seata-order-service # 断言成功后提供的路由地址,lb为负载均衡
predicates:
- Path=/order/** # 断言规则,注意需要和 tomcat servlet容器上下文路径对应
# 库存模块服务
- id: seata-storage-service # 路由Id,没有规则限制,但要唯一
uri: lb://seata-storage-service # 断言成功后提供的路由地址,lb为负载均衡
predicates:
- Path=/storage/** # 断言规则,注意需要和 tomcat servlet容器上下文路径对应
# 处理跨域请求
globalcors:
corsConfigurations:
'[/**]':
allowedHeaders: "*"
allowedOrigins: "*"
allowCredentials: true
allowedMethods:
- GET
- POST
- DELETE
- PUT
- OPTION
注意:predicates的断言规则路径需要和服务的 tomcat servlet容器上下文路径对应,否则无法路由
2、写法二(走配置中心):
bootstrap-dev.yml 配置内容:
server:
port: 6000
spring:
application:
name: gateway-server
cloud:
# nacos注册、配置中心
nacos:
discovery:
server-addr: http://xxx:8848
username: nacos
password: nacos
namespace: dev
group: LEARNING
config:
server-addr: ${spring.cloud.nacos.discovery.server-addr}
username: ${spring.cloud.nacos.discovery.username}
password: ${spring.cloud.nacos.discovery.password}
namespace: ${spring.cloud.nacos.discovery.namespace}
file-extension: yml
extension-configs:
- data-id: application.yml
group: GATEWAY-SERVER
refresh: true
application.yml 配置内容:
server:
port: 6000
spring:
application:
name: gateway-server
cloud:
# 动态路由
gateway:
discovery:
locator:
enabled: true # 开启服务发现让gateway可以发现注册中心的服务,解析微服务名称为主机名和端口,实现动态路由
# lowerCaseServiceId: true # 请求服务是小写的时候改成true(默认为false轻微服务必须是大写)
# 路线
routes:
# mpj服务
- id: mybatis-plus-join-practice # 路由Id,没有规则限制,但要唯一
# http方式
#uri: http://localhost:7000
# lb方式
uri: lb://mybatis-plus-join-practice # 断言成功后提供的路由地址,lb为负载均衡
predicates:
- Path=/mpj/** # 断言规则,注意需要和 tomcat servlet容器上下文路径对应
# provider服务
- id: rabbitmq-provider # 路由Id,没有规则限制,但要唯一
uri: lb://rabbitmq-provider # 断言成功后提供的路由地址,lb为负载均衡
predicates:
- Path=/provider/** # 断言规则,注意需要和 tomcat servlet容器上下文路径对应
# consumer服务
- id: rabbitmq-consumer # 路由Id,没有规则限制,但要唯一
uri: lb://rabbitmq-consumer # 断言成功后提供的路由地址,lb为负载均衡
predicates:
- Path=/consumer/** # 断言规则,注意需要和 tomcat servlet容器上下文路径对应
# 处理跨域请求
globalcors:
corsConfigurations:
'[/**]':
allowedHeaders: "*"
allowedOrigins: "*" #允许哪些网站的跨域请求
#- "http://www.leyou.com"
allowCredentials: true #是否允许携带cookie
allowedMethods:
- GET
- POST
- DELETE
- PUT
- OPTION
注意:
1、predicates 的断言规则路径需要和服务的 tomcat servlet容器上下文路径对应,否则无法路由
2、predicates 路由匹配成功后,转发地址 uri 支持 http、lb 写法
3、一般常用 lb 转发方式,lb 为负载均衡,默认为轮询策略
4、特别注意,使用 lb 方式的前提是本网关服务和 lb 路由的服务必须在同一命名空间、同一分组下,否则无法路由
三、自定义 GateWay 全局过滤器
1、GateWay具有生命周期
【1】PRE:该类过滤器会在被路由之前执行。可以利用这种过滤器实现登录认证、权限鉴定、请求头参数校验、日志记录等
【2】POST:该类过滤器会在路由到服务之后执行。可以利用这种过滤器对响应对象添加响应头、响应状态、响应格式等
【3】当 Gateway 用 Pre Filter、Post Filter 来区分过滤器时,如果这个过滤器是Pre Filter,那么执行顺序和排序顺序相同,如果这个过滤器是Post Filter则执行顺序和排序顺序相反
2、GateWay的过滤器作用范围分为两种:
【1】GatewayFilter:应用到指定路由路由上的过滤器
【2】GlobalFilter:全局过滤器,应用到所有路由上的过滤器(全局生效)
【3】推荐使用全局过滤器,示例:
@Slf4j
@Component
public class GwGlobalFilter implements GlobalFilter, Ordered {
/**
* 处理当前请求,有必要的话通过{@link GatewayFilterChain}将请求交给下一个过滤器处理
*
* @param exchange 请求上下文,里面可以获取Request、Response等信息
* @param chain 放行,用来把请求委托给下一个过滤器
* @return {@code Mono<Void>} 返回标示当前过滤器业务结束
*/
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
System.out.println("GwGlobalFilter 执行了");
// 1.获取请求参数
ServerHttpRequest request = exchange.getRequest();
MultiValueMap<String, String> params = request.getQueryParams();
// 2.获取参数中的 authorization 参数
String auth = params.getFirst("authorization");
// 校验
if ("admin".equals(auth)) {
// 放行
return chain.filter(exchange);
}
//拦截响应
ServerHttpResponse response = exchange.getResponse();
response.setStatusCode(HttpStatus.UNAUTHORIZED);
return response.setComplete();
}
//该过滤器的执行顺序,值越小执行优先级越高
@Override
public int getOrder() {
return 0;
}
}
3、GateWay过滤器执行顺序
【1】如果在路由配置文件中配置了 order 的值,会按照Route中定义的路由顺序依次排序执行
【2】如果RouteFilter实现了 Ordered 接口或者标记 @Order 注解,那么该过滤器执行顺序就是自定义的值
4、GateWay网关小结
【1】多个GlobalFilter可以通过 @Order 或者重写 getOrder() 方法指定每个 GlobalFilter 的执行顺序,order值越小,GlobalFilter执行的优先级越高
【2】当过滤器的 order 值一样时,会按照 defaultFilter > 路由过滤器 > GlobalFilter的顺序执行