1. 基础认识
1.1 项目背景
2. 应用场景
- 路由寻址:用户来访的请求路径,转化成一个服务的内部请求路径,把用户请求导向真正的服务
- 负载均衡:是构建在路由寻址上的一个附加功能,因为某一个服务可能部署了几百台服务器,底层是借助Ribbon实现的
- 限流:作为用户请求的第一站,不放在你身上也说不过去
-
3. 动态路由
3.1 开启动态路由配置
什么是动态路由规则:就是网关层在运行期间,动态的添加路由规则
- 具体的看项目代码
- 启动自动创建理由规则配置
spring.cloud.gateway.discover.locator.enable = true
- 支持服务名称小写配置
spring.cloud.gateway.discover.locator.lower-case-service-id = true
-
3.2 动态路由的基本使用
3.2.1 如何查看生成的路由
// 请求路径:http://localhost:65000/actuator/gateway/routes
[
{
"route_id": "CompositeDiscoveryClient_FEIGN-CONSUMER-ADVANCED",
"route_definition": {
"id": "CompositeDiscoveryClient_FEIGN-CONSUMER-ADVANCED",
"predicates": [
{
"name": "Path",
"args": {
"pattern": "/feign-consumer-advanced/**"
}
}
],
"filters": [
{
"name": "RewritePath",
"args": {
"regexp": "/feign-consumer-advanced/(?<remaining>.*)",
"replacement": "/${remaining}"
}
}
],
"uri": "lb://FEIGN-CONSUMER-ADVANCED",
"order": 0
},
"order": 0
},
{
"route_id": "CompositeDiscoveryClient_GATEWAY-SERVICE",
"route_definition": {
"id": "CompositeDiscoveryClient_GATEWAY-SERVICE",
"predicates": [
{
"name": "Path",
"args": {
"pattern": "/gateway-service/**"
}
}
],
"filters": [
{
"name": "RewritePath",
"args": {
"regexp": "/gateway-service/(?<remaining>.*)",
"replacement": "/${remaining}"
}
}
],
"uri": "lb://GATEWAY-SERVICE",
"order": 0
},
"order": 0
}
]
3.2.2 使用生成的路由访问
http://localhost:65000/gateway-service/sayHi
order
:生效的顺序uri
:指定这个路由访问的是哪一个服务,lb
是指负载均衡predicates
:定义访问这个服务的路径,匹配访问路径,可以配置多个name
:args.pattern
:真实的匹配路径
-
3.3 动态路由的变更
3.3.1 新增路由
// http://localhost:65000/actuator/gateway/routes/新增的路径
// 例如: http://localhost:65000/actuator/gateway/routes/create-path
// 注意是post请求
// 测试新的路由: http://localhost:65000/create-path/sayHi
{
"predicates": [
{
"name": "Path",
"args": {
"_genkey_0": "/create-path/**"
}
}
],
"filters": [
{
"name": "stripPrefix",
"args": {
"_genkey_0": "1"
}
}
],
"uri": "lb://GATEWAY-SERVICE",
"order": 0
}
3.2.3 删除规则
http://localhost:65000/actuator/gateway/routes/需要删除的路径
3.4 路由功能详解
3.4.1 三重路障
3.4.2 工作流程
3.4.3 源码解析
4. 断言
4.1 predicate机制
4.2 断言的作用阶段
一个请求在抵达网关层后,首先要进行断言匹配,只有满足所有断言之后才会进入
Filter
阶段4.3 常见断言介绍
4.3.1 路径匹配Path断言
4.3.2 Method断言
4.3.3 RequestParam匹配
4.3.4 Header断言
4.3.5 cookie断言
4.3.6 时间片段匹配
4.4 断言实战
4.4.1 利用path实现url的映射
spring:
cloud:
gateway:
routes:
- id: feignclient
uri: lb://FEIGN-CLIENT
predicates:
- Path=/yml/**
filters:
- StripPrefix=1
```java package com.yihua.cloud;
import org.springframework.cloud.gateway.route.RouteLocator; import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.core.annotation.Order; import org.springframework.http.HttpMethod;
/**
- 配置网关层的路由规则 *
- @author YiHua
@date 2022/6/24 */ @Configuration public class GatewayConfiguration {
@Bean @Order public RouteLocator customizeRoutes(RouteLocatorBuilder builder) {
return builder.routes()
.route(predicateSpec -> predicateSpec.path("/java/**")
.and().method(HttpMethod.GET)
.and().header("name")
.filters(gatewayFilterSpec -> gatewayFilterSpec.stripPrefix(1)
.addRequestHeader("java-param", "gateway-config"))
.uri("lb://FEIGN-CONSUMER-ADVANCED")).build();
4.4.2 利用after断言实现简单的定时秒杀任务
```java package com.yihua.cloud;
import org.springframework.cloud.gateway.route.RouteLocator; import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.core.annotation.Order; import org.springframework.http.HttpMethod;
import java.time.ZonedDateTime;
/**
- 配置网关层的路由规则 *
- @author YiHua
@date 2022/6/24 */ @Configuration public class GatewayConfiguration {
@Bean @Order public RouteLocator customizeRoutes(RouteLocatorBuilder builder) {
return builder.routes()
// 利用path实现url的映射
.route(predicateSpec -> predicateSpec.path("/java/**")
.and().method(HttpMethod.GET)
.and().header("name")
.filters(gatewayFilterSpec -> gatewayFilterSpec.stripPrefix(1)
.addRequestHeader("java-param", "gateway-config"))
.uri("lb://FEIGN-CONSUMER-ADVANCED"))
// 利用after断言实现简单的定时秒杀任务
.route(predicateSpec -> predicateSpec.path("/seckill/**")
// 表示项目启动完成的1分钟后这个断言开始生效
.and().after(ZonedDateTime.now().plusMinutes(1))
.filters(gatewayFilterSpec -> gatewayFilterSpec.stripPrefix(1))
.uri("lb://FEIGN-CONSUMER-ADVANCED"))
.build();
4.5 自定义断言
4.6 断言的匹配顺序
5. 过滤器
5.1 过滤器的执行阶段
5.2 过滤器的执行顺序
5.3 常见的过滤器
5.3.1 header过滤器
5.3.2 StripPrefix过滤器
5.3.3 PrefixPath过滤器
5.3.4 RedirectTo过滤器
5.3.5 SaveSession过滤器
5.4 自定义过滤器
5.4.1 普通的过滤器
- 只需要实现
GatewayFilter
接口重写filter()
方法 两个关键参数解析
实现接口由
GatewayFilter
�,更换成GlobalFilter
,实现的代码都不需要变动- 移除配置,全局过滤器不需要配置,它会作用在每一个路由上
5.3.3 接口计时过滤器
5.3.4 权限验证过滤器
6. 网关层的其它实践
6.1 统一异常处理
6.2 限流
频繁调用鉴权服务的令牌校验接口产生的问题?
- 一般的鉴权服务不是集成在网关层的,那么每一次的令牌的校验都需要发送一个http请求到鉴权服务。那么每一次方法的调用都会触发请求,并发 + RT(响应时间)都会增加
- 解决方式:令牌的颁发采用非对称加密,然后令牌的校验下放到网关层,网关层拿着私钥进行解密,然后直接在网关层校验令牌
7. 微服务下的权限控制
7.1 网关层老大
auth
服务:令牌颁发gateway
服务:令牌校验、权限校验
这里提示:用redis做缓存权限类型
7.2 业务层老大
auth
服务:令牌颁发business
服务:令牌校验、权限校验
7.3 频繁调用鉴权服务的令牌校验接口产生的问题?
- 一般
令牌校验(Token Verify)
服务不是集成在网关层/业务层(gateway/business)
,那么每一次的Token Verify
都需要发送一个http
请求到鉴权服务(Auth Service)
- 那么每一次方法的调用都会触发请求,并发 +
RT
(响应时间)都会增加 - 解决方式:不管是哪一种方式,令牌的颁发采用非对称加密,然后
Token Verify
下放到gateway/business
,gateway/business
拿着私钥进行解密,然后直接Token Verify
,这样就不用通过Auth Service