1. 简介
1.1 概述
SpringCloud Gateway使用的是Webflux中的reactor-netty响应式编程组件,底层使用了Netty通讯框架
1.2 源码架构
1.3 作用
- 反向代理
- 鉴权
- 限流
- 熔断
- 日志监控
- ……
1.4 微服务架构中网关在哪里
2. Zuul与GateWay的区别
- netflix不太靠谱,zuul2.0一直跳票,迟迟不发布,且2.0发布后Spring也不集成了…
- SpringCloud Gateway模型具有如下特性
- GateWay使用了Spring最新的WebFlux框架,WebFlux基于Netty的异步非阻塞式IO网络模型
- Zuul1.x模具有如下特性
- GateWay与Zuul的区别
2. 三大核心概念
2.1 Route(路由)
路由是构建网关的基本模块,它由ID,目标URI,一系列的断言和过滤器组成,如断言为true则匹配该路由
2.2 Predicate(断言)
参考的是Java8的java.util.function.Predicate 开发人员可以匹配HTTP请求中的所有内容(请求头、请求方式、Cookie或请求参数等),如果请求与断言相匹配则进行路由
2.3 Filter(过滤)
指的是Spring框架中GatewayFilter的实例,使用过滤器,可以在请求被路由前或路由后对请求进行修改。
3. GateWay的工作流程
核心:路由转发+执行过滤器链
4. 入门案例
4.1 需求
新建一个9527端口Module做网关,拦截8001payment微服务下的/get/请求和/lb/请求
4.2 依赖
<!--gateway-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
4.3 yaml
server:
port: 9527
spring:
application:
name: cloud-gateway
cloud:
gateway:
discovery:
locator:
enabled: true # 开启从注册中心动态创建路由的功能,利用微服务名称进行路由
routes:
- id: payment_route # 路由的id,没有规定规则但要求唯一,建议配合服务名
# 单实例:匹配后提供服务的路由地址
uri: http://localhost:8001
# 多实例,动态路由,使用服务名,需要注意的是uri的协议lb,表示启用Gateway的负载均衡功能.
#uri: lb://cloud-payment-service
predicates:
- Path=/payment/get/** # 断言,路径相匹配的进行路由
- id: payment_route2
# 单实例:匹配后提供服务的路由地址
uri: http://localhost:8001
# 多实例,动态路由,使用服务名,需要注意的是uri的协议lb,表示启用Gateway的负载均衡功能.
#uri: lb://cloud-payment-service
predicates:
Path=/payment/lb/** #断言,路径相匹配的进行路由
eureka:
instance:
hostname: cloud-gateway-service
client:
fetch-registry: true
register-with-eureka: true
service-url:
defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka
4.4 测试
- 启动Eureka、8001、gateway相应的微服务
- 访问http://localhost:9527/payment/get/1可以得到与http://localhost:8001/payment/get/1同样的效果
5. Gateway网关路由的两种配置方式
5.1 yaml配置
参考:4.3 yaml
5.2 代码配置
注入
RouteLocator
的Bean
/**
* @author JShawn 2021/3/25 20:02
*/
@Configuration
public class GateWayConfig {
/**
* 配置了一个id为path_route_atguigu的路由规则,
* 当访问地址http://localhost:9527/guonei时会自动转发到地址http://news.baidu.com/guonei
*/
@Bean
public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
RouteLocatorBuilder.Builder routes = builder.routes();
routes.route("path_route_atguigu",r -> r.path("/guonei").uri("http://news.baidu.com/guonei")).build();
return routes.build();
}
}
6. 动态路由
由于实际开发中微服务有可能是多实例节点,因此需要通过服务名
spring.application.name
优化配置中写死的uri 默认情况下Gatway会根据注册中心注册的服务列表,以注册中心上微服务名为路径创建动态路由进行转发,从而实现动态路由的功能
6.1 配置
完整配置参考:4.3 yaml中注释的uri多实例部分
# lb://serverName是spring cloud gatway在微服务中自动为我们创建的负载均衡uri
# 单实例:匹配后提供服务的路由地址
#uri: http://localhost:8001
# 多实例,动态路由,使用服务名,需要注意的是uri的协议lb,表示启用Gateway的负载均衡功能.
uri: lb://cloud-payment-service
7. Predicate
启动gateway时可以看到日志打印如下,这些就是gateway支持的不同方式的断言
7.1 使用
7.2 常用的Route Predicate
常用的Route Predicate | 示例 | 说明 |
---|---|---|
1.After Route Predicate | 某一时间点之后,则执行路由 | |
2.Before Route Predicate | 略,参考同上 | 某一时间点之前,则执行路由 |
3.Between Route Predicate | 略,参考同上 | 某一时间范围内,则执行路由 |
4.Cookie Route Predicate | - 不带cookies访问 |
- 带上cookies访问
- 加入curl返回中文乱码
https://blog.csdn.net/leedee/article/details/82685636 | 通过获取对应的Cookie name value和正则表达式去匹配,如果匹配上就会执行路由,如果没有匹配上则不执行 |
| 5.Header Route Predicate |
| 两个参数:一个是请求头名称和一个正则表达式,这个属性值和正则表达式匹配则执行 |
| 6.Host Route Predicate | | 接收一组匹配的域名列表,这个模板是一个ant分隔的模板,用.号作为分隔符。它通过参数中的主机地址作为匹配规则 |
| 7.Method Route Predicate | | 匹配请求方式:GET、POST、PUT、DELETE |
| 8.Path Route Predicate | | 路径匹配:路径相同则放行 |
| 9.Query Route Predicate |
| 匹配请求参数方式
支持传入两个参数:一个属性名、一个属性值,属性值可以是正则表达式 |
| 10.RemoteAddr Route Predicate | | |
| 11.Weight Route Predicate | | |
| 总结 | | |
| 说白了,Predicate就是为了实现一组匹配规则, 让请求过来找到对应的Route进行处理
| | |
8. Filter
8.1 Spring Cloud Gateway的filter
8.1.1 生命周期
- pre
- post
8.1.2 种类
8.1.2.1 GatewayFilter
8.1.2.2 GlobalFilter
8.2 常用的GatewayFilter
8.2.1 AddRequestParameterGateWayFactory
8.2.2 其他省略,主要是自定义
8.3 自定义Filter
8.3.1 作用
全局日志记录、统一网关鉴权、……
8.3.2 自定义全局GlobalFilter
需求:访问接口必须带上uname参数,否则不予访问
8.3.2.1 实现两个接口 GlobalFilter
, Ordered
/**
* @author JShawn 2021/3/25 20:57
*/
@Component
@Slf4j
public class MyLogGatewayFilter implements GlobalFilter, Ordered {
/**
* 过滤逻辑
* @param exchange
* @param chain
* @return
*/
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
log.info("come in global filter: {}", new Date());
ServerHttpRequest request = exchange.getRequest();
String uname = request.getQueryParams().getFirst("uname");
if (uname == null) {
log.info("用户名为null,非法用户");
exchange.getResponse().setStatusCode(HttpStatus.NOT_ACCEPTABLE);
return exchange.getResponse().setComplete();
}
// 放行
return chain.filter(exchange);
}
/**
* 相当于load-on-startup,定义过滤器链顺序
* 过滤器加载的顺序越小,优先级别越高
* @return
*/
@Override
public int getOrder() {
return 0;
}
}
8.3.2.2 测试
- 成功
- 失败
9. 网关解决全局跨域问题
Springboot1.0 二十二、跨域解决-CORS 2.2 配置类———全局配置
10. 解决绕过网关直连微服务问题
- 网络隔离:常用,只暴露网关端口、防火墙
- 网关增加全局Fliter:在Fliter增加Request Header
- 静态请求头:参考:8.2.1
- 动态请求头:参考:SpringCloud确保服务只能通过gateway转发访问,禁止直接调用接口访问