目录
一, Gateway服务网关
1.1 为什么需要网关
1.2 网关的实现方式
1.3 Gateway快速入门
1. 创建gateway服务,引入依赖
2. 编写启动类
3. 编写基础配置和路由规则
4. 重启测试
5. 网关路由的流程图
6. 总结
二, Gateway断言工厂
三, 过滤器工厂
3.1 路由过滤器的种类
1. 请求头过滤器
2. 默认过滤器
3. 总结
3.2 全局过滤器
1. 全局过滤器的作用
2. 自定义全局过滤器
3. 过滤器执行的顺序
SpringCloud Gateway是SpringCloud的一个全新项目,该项目基于Spring 5.0,SpringBoot 2.0,和Project Reactor等响应式编程和事件流技术开发的网关,它旨在为微服务架构提供一种简单有效的统一API路由管理方式.
Gateway网关是我们服务的"守门神",所有微服务的同意入口;
网关的核心功能特性:
架构图:
权限控制:网关作为微服务的入口,需要校验用户是否有请求资格,如果没有进行拦截
路由和负载均衡:一切请求都必须经过gateway,但网关不处理业务,而是根据某种规则,把请求转发到某个微服务,这个过程叫做路由;当然路由的目标服务有多个时,还需要做负载均衡
限流: 当请求流量过高时,在网关中按照下流的微服务能够接受的速度来放行请求,避免服务压力过大
在SpringCloud中网关的实现包括两种:
Zuul是基于servlet的实现,属于阻塞式编程,而SpringCloudGateway则是基于Spring5中提供的Wlux,属于响应式编程的实现,具备更好的性能.
下面,我们演示下网关的基本路由功能,基本步骤如下:
创建服务:
引入服务:
org.springframework.cloud
spring-cloud-starter-gateway
com.alibaba.cloud
spring-cloud-starter-alibaba-nacos-discovery
创建application.yml文件,内容如下:
server:
port: 10010 # 网关端口
spring:
application:
name: gateway # 服务名称
cloud:
nacos:
server-addr: localhost:8848 # nacos地址
gateway:
routes: # 网关路由配置
- id: user-service # 路由id,自定义,只要唯一即可
# uri: http://127.0.0.1:8081 # 路由的目标地址 http就是固定地址
uri: lb://userservice # 路由的目标地址 lb就是负载均衡,后面跟服务名称
predicates: # 路由断言,也就是判断请求是否符合路由规则的条件
- Path=/user/** # 这个是按照路径匹配,只要以/user/开头就符合要求
我们将Path规则的一切请求,都代理到uri参数指定地址;
本例中,我们将/user/**开头的请求,代理到 lb://userservice,lb是负载均衡,根据服务名拉取服务列表,实现负载均衡.
重启网关,访问http://localhost:10010/user/1时(因为我们这里设置的网关服务的端口号是10010),复合/user/**规则,请求转发到uri:http://userservice/user/1,得到的结果:
整个访问流程如下:
网关搭建步骤:
路由配置规则:
我们在配置文件中写的断言规则只是字符串,这些字符串会被Predicate Factory读取并处理,转变为路由判断的条件,例如 Path=/user/**是按照路径匹配,这个规则是由org.springframework.cloud.gateway.handler.predicate.PathRoutePredicateFactory类来处理的,像这样的断言工厂在SpringCloudGateway还有十几个:
名称 | 说明 | 示例 |
---|---|---|
After | 是某个时间点后的请求 | - After=2037-01-20T17:42:47.789-07:00[America/Denver] |
Before | 是某个时间点之前的请求 | - Before=2031-04-13T15:14:47.433+08:00[Asia/Shanghai] |
Between | 是某两个时间点之前的请求 | - Between=2037-01-20T17:42:47.789-07:00[America/Denver], 2037-01-21T17:42:47.789-07:00[America/Denver] |
Cookie | 请求必须包含某些cookie | - Cookie=chocolate, ch.p |
Header | 请求必须包含某些header | - Header=X-Request-Id, \d+ |
Host | 请求必须是访问某个host(域名) | - Host=.somehost.org,.anotherhost.org |
Method | 请求方式必须是指定方式 | - Method=GET,POST |
Path | 请求路径必须符合指定规则 | - Path=/red/{segment},/blue/** |
Query | 请求参数必须包含指定参数 | - Query=name, Jack或者- Query=name |
RemoteAddr | 请求者的ip必须是指定范围 | - RemoteAddr=192.168.1.1/24 |
Weight | 权重处理 |
我们只需要掌握Path这种路由工程就可以了.
GatewayFilter是网关提供的一种过滤器,可以对进入网关的请求和微服务返回的响应结果做处理:
Spring提供了31种不同的路由过滤器工厂,例如:
名称 | 说明 |
---|---|
AddRequestHeader | 给当前请求添加一个请求头 |
RemoveRequestHeader | 移除请求中的一个请求头 |
AddResponseHeader | 给响应结果中添加一个响应头 |
RemoveResponseHeader | 从响应结果中移除有一个响应头 |
RequestRateLimiter | 限制请求的流量 |
下面我们以AddRequestHeader为例来讲解;
需求:给所有进入userservice的请求添加一个请求头:Truth=learning
只需要修改gateway服务的application.yml文件,添加路由头过滤即可:
spring:
cloud:
gateway:
routes:
- id: user-service
uri: lb://userservice
predicates:
- Path=/user/**
filters: # 过滤器
- AddRequestHeader=Truth, learning # 添加请求头(这里的,的左右两边相当于key和value)
当前过滤器写在userservice路由下,因此仅仅对访问userservice的请求有效.
修改UserController里面的代码获取header:
如果要对所有的路由都生效,则可以将过滤器工厂写到default下,格式如下:
spring:
cloud:
gateway:
routes:
- id: user-service
uri: lb://userservice
predicates:
- Path=/user/**
default-filters: # 默认过滤项
- AddRequestHeader=Truth, learning
此时可以发现default-filter是和routes在同一级的.
过滤器的作用是什么?
default-filter的作用是什么?
上面提到网关提供了31种过滤器,但每一种过滤器的作用都是固定的,如果我们希望拦截请求,做自己的业务逻辑没办法实现.
全局过滤器的作用也是处理一切进入网关的请求和微服务响应,与GatewayFilter的作用是一样的,区别在于GatewayFilter通过配置定义,处理逻辑是固定的,而GlobalFilter的逻辑需要自己写代码实现.
定义的方式是实现GlobalFilter接口:
public interface GlobalFilter {
/**
* 处理当前请求,有必要的话通过{@link GatewayFilterChain}将请求交给下一个过滤器处理
*
* @param exchange 请求上下文,里面可以获取Request、Response等信息
* @param chain 用来把请求委托给下一个过滤器
* @return {@code Mono} 返回标示当前过滤器业务结束
*/
Mono filter(ServerWebExchange exchange, GatewayFilterChain chain);
}
在filter中编写自定义逻辑,可以实现以下功能:
需求:定义全局过滤器,拦截请求,判断请求的参数是否满足下面条件:
如果同时满足则放行,否则拦截;
实现:
在gateway定义一个过滤器:
@Order(-1)
@Component
public class AuthorizeFilter implements GlobalFilter {
@Override
public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) {
// 1.获取请求参数
MultiValueMap params = exchange.getRequest().getQueryParams();
// 2.获取authorization参数
String auth = params.getFirst("authorization");
// 3.校验
if ("admin".equals(auth)) {
// 放行
return chain.filter(exchange);
}
// 4.拦截
// 4.1.禁止访问,设置状态码
exchange.getResponse().setStatusCode(HttpStatus.FORBIDDEN);
// 4.2.结束处理
return exchange.getResponse().setComplete();
}
}
请求进入网关会碰到三类过滤器:当前路由的过滤器,DefaultFilter,GlobalFilter,请求路由后,会将当前路由过滤器和DefaultFilter,GlobalFilter,合并到一个过滤器链(集合)中,排序后依次执行每个过滤器:
排序的规则是什么呢?
详细内容,可以查看源码:
org.springframework.cloud.gateway.route.RouteDefinitionRouteLocator#getFilters()
方法是先加载defaultFilters,然后再加载某个route的filters,然后合并;
org.springframework.cloud.gateway.handler.FilteringWebHandler#handle()
方法会加载全局过滤器,与前面的过滤器合并后根据order排序,组织过滤器链.