1.1 三大术语Gateway 是基于Spirng5.0,Spring Boot2.0等技术的网关,旨在为微服务架构提供一种简单有效的统一的API路由管理方式。
Gateway是基于WebFlux框架实现的,而==WebFlux底层使用了高性能的通信框架Netty==。
Gateway不仅提供统一路由方式,并且基于Filter链的方式提供了网关基本的功能:安全、监控、限流等。
和Zuul主要的区别在于底层通信框架
Filter(过滤器)
可以拦截和修改请求,并且对上游的响应进行二次处理,GatewayFilter,可以在请求之前或者之后执行业务逻辑
Route(路由)
一个路由由id(自定义路由id,必须唯一)、目标url(目标服务地址)、一组断言和一组过滤器组成
Predicate(断言)
可以使用断言来匹配HTTP请求,支持多种方式:Path、Query、Method、Header等,必须遵循key=value的形式
1.2 Gateway处理流程客户端从浏览器向Gateway发起请求,由DispatcherServlet负责调度,遍历Handler Mapping找到匹配的,将请求发送到WebHandler,Handler通过过滤器链将请求发送到实际处理业务逻辑的服务。
虚线分开是因为过滤器可能在发送代理请求之前pre,或者之后post执行业务逻辑,
Filter在pre过滤器中可以做参数校验、权限校验、流量监控、日志输出、协议转换等,在post类型过滤器中可以响应内容、响应头修改等。
2 路由配置2.1 配置文件id、uri、predicates
spring:
cloud:
gateway:
routes:
- id: provider
uri: lb://nacos-provider
predicates:
- Path=/nacos-provider/**
filters:
- StripPrefix=1
- id: consumer
uri: lb://nacos-consumer
predicates:
- Path=/nacos-consumer/**
filters:
- StripPrefix=1
id:唯一的路由id
uri:转到的目标服务地址
predicates:路由条件,接收一个参数,返回一个boolean结果,有多种默认的方法供使用
filters:过滤器
2.2 基于代码配置@Configuration
public class CustomRouteRule {
@Bean
public RouteLocator customRouteLocator(RouteLocatorBuilder builder){
return builder
.routes()
.route("custom_id",r -> r.path("/nacos-provider/**")
.filters(f->f.stripPrefix(1))
.uri("lb://nacos-provider"))
.build();
}
}
3 路由匹配规则
3.1 断言Gateway的predicates功能很强大,通过WebFlux的handlermapping作为底层匹配路由转发,多个predicate可以组合使用
predicate接受一个参数,返回一个boolean结果,包含多种默认方法将predicate组合成其他复杂逻辑
转发规则:
| 规则 | 实例 | 说明 |
|---|---|---|
| Path | -Path=/test/,/rule/ | 当请求路径为test、rule开头时,转发请求 |
| Before | -Before=2021-01-20T17:42:47.789-07:00[America/Denver] | 在某个时间之前的请求会被转发 |
| After | -After=2021-01-20T17:42:47.789-07:00[America/Denver] | 在某个时间之后的请求会被转发 |
| Between | -Between=-Before=2021-01-20T17:42:47.789-07:00[America/Denver],-Before=2021-04-20T17:42:47.789-07:00[America/Denver] | 在时间段内请求会被转发 |
| cookie | -cookie=cookieName,pattern | 第一个参数cookie的名字,第二个参数是正则表达式,满足条件转发 |
| Header | -Header=X-Request-Id,d+ | 请求头中携带参数X-Request-Id或者满足d+的请求会被转发 |
| Host | -Host=www.aaa.com | 当主机名为www.aaa.com的时候会被转发 |
| Method | - Method=GET | 只有GET请求会被转发,还可以是POST,PUT等方式 |
| Query | - Query=name | 请求参数中含有name字段才会被转发 |
1. 通过请求参数匹配
spring:
cloud:
gateway:
routes:
- id: nacos-provider
uri: lb://nacos-provider
predicates:
- Query=name
# 请求中含有name字段的会被抓饭
#===============
spring:
cloud:
gateway:
routes:
- id: nacos-provider
uri: lb://nacos-provider
predicates:
- Query=name,z.
# 请求参数中有name字段,并且是以z开头的请求会被转发
2. 通过Header匹配
Header Predicate接受两个参数,一个header中舒敏名称,一个正则表达式
spring:
cloud:
gateway:
routes:
- id: nacos-provider
uri: lb://nacos-provider
predicates:
- Header=X-Request-age,d+
# curl http://localhost:10001/nacos-provider -H "X-Request-age:22"
3. 通过cookie匹配
接受两个参数,一个是cookie name,一个是正则表达式
spring:
cloud:
gateway:
routes:
- id: provider
uri: lb://provider
predicates:
- cookie=sessionId,aaa
# curl http://localhost:10001/provider --cookie "sessionId=aaa"
4. 通过Host匹配
Host Predicate接受一组参数,一组匹配的域名列表,这个模板是一个ant分隔的模板,用 . 隔开,通过参数中的主机地址作为匹配规则
spring:
cloud:
gateway:
routes:
- id: provider
uri: lb://nacos-provider
predicates:
- Host=**.baidu.com
# curl http://localhost:10001/nacos-provider -H "Host:www.baidu.com"
# curl http://localhost:10001/nacos-provider -H "Host:test.baidu.com"
5. 通过请求方式匹配
POST、GET 、PUT、 DELETE
spring:
cloud:
gateway:
routes:
- id: provider
uri: lb://nacos-provider
predicates:
- Method=GET
# curl http://localhost:10001/provider
6. 通过请求路径匹配
spring:
cloud:
gateway:
routes:
- id: provider
uri: lb://nacos-provider
predicates:
- Path=/provider/**
# curl http://localhost:10001/provider/feign
7. 通过IP地址匹配
接受IPV4 或 IPV6 字符串列表,最小为1
spring:
cloud:
gateway:
routes:
- id: provider
uri: lb://nacos-provider
predicates:
- RemoteAddr=172.168.1.1/24
8. 组合使用
当多个predicate在同一个路由时,请求需要同时满足才能被匹配,当一个请求满足多个路由时,第一个匹配成功的转发
spring:
cloud:
gateway:
routes:
- id: provider
uri: lb://nacos-provider
predicates:
- Host=**.baidu.com
- Path=/provider/**
- Method=GET
- Header=X-Request-age,d+
- Query=name,z.
- Query=name
- cookie=cookieName,coki
3.2 过滤器规则
当配置多个Filter时,优先定义的会被调用,剩余的filter不会生效
1. 过滤器规则
| 过滤规则 | 实例 | 说明 |
|---|---|---|
| PrefixPath | - PrefixPath=/provider | 请求路径千加上provider |
| RewritePath | - RewritePath=/provider/,/nacos-provider/test | 访问/provider请求会被转发到/nacos-provider/test上 |
| SetPath | - Setpath=/provider/{path} | 通过模板设置路径,转发的规则会在路径前增加provider,{path}标识原请求路径 |
| RedirectTo | 重定向 | |
| RemoveRequestHeader | 去掉某个请求头 |
2. PrefixPath
# 对所有请求路径增加 前缀 hello
spring:
cloud:
gateway:
routes:
- id: provider
uri: lb://nacos-provider
filters:
- PrefixPath=/hello
3. RedirectTo
# 重定向 包含重定向地址和返回码
spring:
cloud:
gateway:
routes:
- id: provider
uri: lb://nacos-provider
filters:
- RedirectTo=404,http://abc.com
4. RemoveRequestHeader
# 去掉某个请求头信息 X-Request-Id
spring:
cloud:
gateway:
routes:
- id: provider
uri: lb://nacos-provider
filters:
- RemoveRequestHeader=X-Request-Id
5. RemoveResponseHeader
# 去掉某个回执响应头信息 X-Request-param
spring:
cloud:
gateway:
routes:
- id: provider
uri: lb://nacos-provider
filters:
- RemoveResponseHeader=X-Request-param
6. RemoveRequestParameter
# 去掉某个请求参数 请求参数name
spring:
cloud:
gateway:
routes:
- id: provider
uri: lb://nacos-provider
filters:
- RemoveRequestParameter=name
7. RewritePath
# 改写路径 /where/... 改写为 /hello/...
spring:
cloud:
gateway:
routes:
- id: provider
uri: lb://nacos-provider
filters:
- RewritePath=/where(?/?.*),/hello(?/?.*)
8. SetPath
# 设置请求路径 与Rewritepath类似
# 将/xxx/hello 请求 设置为 /hello 请求
spring:
cloud:
gateway:
routes:
- id: provider
uri: lb://nacos-provider
predicates:
- Path=/provider/{segment}
filters:
- SetPath=/{segment}
9. SetRequestHeader
# 设置请求头
spring:
cloud:
gateway:
routes:
- id: provider
uri: lb://nacos-provider
filters:
- SetRequestHeader=X-Request-Hello,Name
10. SetStatus
# 设置状态码
spring:
cloud:
gateway:
routes:
- id: provider
uri: lb://nacos-provider
filters:
- SetStatus=404
11. StripPrefix
# 跳过指定路径,过滤掉路径前几个
# /a/b/hello --> /hello
spring:
cloud:
gateway:
routes:
- id: provider
uri: lb://nacos-provider
filters:
- StripPrefix=2
12. RequestSize
# 请求大小 超过限制会返回413
spring:
cloud:
gateway:
routes:
- id: provider
uri: lb://nacos-provider
filters:
- name: RequestSize
args:
maxSize: 10000000
13. Default-filters
# 对所有请求添加过滤器
spring:
cloud:
gateway:
default-filters:
- PrefixPath=/hello
3.3 过滤器分类
生命周期分类
| 生命周期 | 作用 |
|---|---|
| pre | 路由调用之前利用过滤器实现身份验证、在集群中选择请求转发的微服务等 |
| post | 在微服务执行以后,可以用来为响应添加header、收集统计信息和指标,将响应发送给客户端 |
过滤器类型分类
| 过滤器类型 | 影响范围 |
|---|---|
| GatewayFilter | 应用到单个路由 |
| GlobalFilter | 应用到所有路由 |
全局过滤器一般用的较多,可以用来定义一些黑名单校验、限流功能等:
@Slf4j
@Component
public class TestFilter implements GlobalFilter, Ordered {
private static List blackList = new ArrayList<>();
static {
blackList.add("0:0:0:0:0:0:0:1"); // 模拟本机地址
}
@Override
public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) {
// 获取客户端ip,判断是否在黑名单中,在就拒绝访问,不在就放行
ServerHttpRequest request = exchange.getRequest();
ServerHttpResponse response = exchange.getResponse();
// 从request中获取客户端ip
String clientIp = request.getRemoteAddress().getHostString();
// 比较
if (blackList.contains(clientIp)) {
// 拒绝访问
response.setStatusCode(HttpStatus.UNAUTHORIZED);
log.info("IP: "+clientIp+" 在黑名单中,拒绝访问");
String msg = "请求被禁止!";
DataBuffer wrap = response.bufferFactory().wrap(msg.getBytes(StandardCharsets.UTF_8));
return response.writeWith(Mono.just(wrap));
}
return chain.filter(exchange);
}
@Override
public int getOrder() {
return 0; // 数值越小,优先级越高
}
}
4 跨域请求
spring:
cloud:
gateway:
globalcors:
cors-configurations:
'[/**]':
allowed-origins: "*"
allowed-headers: "*"
allowed-credentials: true
allowed-methods:
- GET
- POST
- DELETE
- OPTION
- PUT
5 Gateway高可用
网关是一个核心的部件,如果挂掉,所有的请求就无法路由,因此需要实现gateway高可用
实现:启动多个gateway实例来实现gateway高可用,在gateway上的上游使用Nginx做代理,实现负载均衡
# 配置多个Gateway
upstream gateway{
server 127.0.0.1:10001
server 127.0.0.1:20001
}
location / {
proxy_pass http://gateway;
}
*]':
allowed-origins: "*"
allowed-headers: "*"
allowed-credentials: true
allowed-methods:
- GET
- POST
- DELETE
- OPTION
- PUT
5 Gateway高可用
网关是一个核心的部件,如果挂掉,所有的请求就无法路由,因此需要实现gateway高可用
实现:启动多个gateway实例来实现gateway高可用,在gateway上的上游使用Nginx做代理,实现负载均衡
# 配置多个Gateway
upstream gateway{
server 127.0.0.1:10001
server 127.0.0.1:20001
}
location / {
proxy_pass http://gateway;
}



