1. 简介
Spring Cloud Gateway 是 Spring 官方基于 Spring 5.0,Spring Boot 2.0 和 Project Reactor 等技术开发的网关,旨在为微服务架构提供一种简单而有效的统一的 API 路由管理方式,统一访问接口。Spring Cloud Gateway 作为 Spring Cloud 生态系中的网关,目标是替代 Netflix ZUUL,其不仅提供统一的路由方式,并且基于 Filter 链的方式提供了网关基本的功能,例如:安全,监控/埋点,和限流等。它是基于Nttey的响应式开发模式。
2 核心概念
1. 路由(route) 路由是网关最基础的部分,路由信息由一个ID、一个目的URL、一组断言工厂和一
组Filter组成。如果断言为真,则说明请求URL和配置的路由匹配。
2. 断言(predicates) Java8中的断言函数,Spring Cloud Gateway中的断言函数输入类型是
Spring5.0框架中的ServerWebExchange。Spring Cloud Gateway中的断言函数允许开发者去
定义匹配来自Http Request中的任何信息,比如请求头和参数等。
3. 过滤器(filter) 一个标准的Spring webFilter,Spring Cloud Gateway中的Filter分为
两种类型,分别是Gateway Filter和Global Filter。过滤器Filter可以对请求和响应进行处理。
如:
spring:
cloud:
gateway:
routes:
- id: product_router #路由的ID,没有固定规则但要求唯一,建议配合服务名
uri: lb://PRODUCT #匹配后提供服务的路由地址 实现请求负载均衡处理
predicates: # 断言,路径相匹配的进行路由
- Path=/product/**
- Method=GET
filters: #过滤规则
- AddRequestHeader=User-Name, chenyn
- AddRequestParameter=color, blue
3 案例:
各微服务端口号:
分类微服务(服务消费者)存在方法:
@Autowired
private ProductClient productClient; //远程调用商品微服务product接口
@GetMapping("/category")
public String category(){
log.info("分类微服务");
String result = productClient.product();
return result;
}
商品微服务(服务提供者)存在方法:
@GetMapping("/list")
public String list(HttpServletRequest request,String color){
log.info("商品列表服务");
return "list ok当前提供服务端口:"+port;
}
@GetMapping("/product")
public String product() throws InterruptedException {
log.info("进入商品服务.....");
return "product ok,当前提供服务端口:"+port;
}
分别测试两个独立的微服务是否可以访问:
测试服务消费者接口
测试服务消提供者接口
现在添加网关微服务,进行配置yml
server:
port: 7979
spring:
application:
name: GATEWAY
cloud:
consul:
host: localhost
port: 8500
gateway:
routes:
- id: product_router #路由对象唯一标识
uri: http://localhost:8788 #用来类别服务地址 http://localhost:8788/list
predicates: #断言 用来配置路由规则
- Path=/product
- id: category_router #路由对象唯一标识
uri: http://localhost:8787 #用来类别服务地址 http://localhost:8787/list
predicates: #断言 用来配置路由规则
- Path=/category
测试访问通过网关请求:
网关路由解析规则:
当我们访问http://localhost:7979/product时 网关微服务就会在routes列表当中查找有没有 和*/product* 匹配的Path路由规则
以上网关的配置一定是存在问题的,比如:
以上我们只是访问一个路径(/product)进行转发(转发到http://localhost:8788上)
而实际的微服务当中不可能存在一个访问路径,比如案例当中的商品微服务还存在一个list方法,这个时候我们又怎么让网关帮助我们转发呢?
配置如下:
测试访问:
以上还是存在一个问题;如果商品微服务当中存在多个服务路径,那我们就需要在网关配置文件当中配置多个路由规则,就像上面增加的list路径。
而gateway网关支持我们使用通配的方式去匹配路由规则
测试:
以上可以发现路由规则这块 我们可以配置一个,多个以及 通配的方式进行路由配置
4.配置路由服务负载均衡
现有路由配置方式,都是基于服务地址写死的路由转发,能不能根据服务名称进行路由转发同时实现负载均衡的呢?
uri : uri以 lb: //开头(lb代表从注册中心获取服务),后面接的就是你需要转发到的服务名称
5 网关断言和过滤
其实在springcloud设计网关的时候,他其实将网关划分了
断言和过滤器
网关gateway = 断言(predicate) + 过滤(filter)
断言(predicate):当请求到达网关,网关在转发请求之前做的一些处理 满足断言放行请求,不满足断言立即返回。
过滤(filter):当请求满足断言的所有条件之后,会向后端服务转发,在向后端服务转发之前会经过一系列过滤处理。
以上我们配置的网关配置是没有加任何的过滤的,我们只配置了断言,只要断言一过,就拿着路径直接请求后端服务。其实还有一个过滤配置。
无论是断言还是过滤,springcloud都给我们配置了大量的断言工厂和过滤工厂
网关断言使用 Route Predicate Factories
1 - Path=/product/** :路径断言,路径匹配成功时候转发到后台服务 作用如以上案例
2 - After=2017-01-20T17:42:47.789-07:00[America/Denver](区域时间):代表该路由规则必须在指定时间之后才能生效
案例如下:
在2021-06-13 21:29:22之前访问:
在2021-06-13 21:29:22之后访问:
3 - Before=2021-06-13T21:40:22.124+08:00[Asia/Shanghai] (区域时间):代表该路由规则必须在指定时间之前才能生效
4 - Between=2021-04-20T10:23:22.124+08:00[Asia/Shanghai],2021-04-20T10:25:22.124+08:00[Asia/Shanghai](区域时间):代表该路由规则必须在指定时间之间才能生效
5 - Cookie=name,chenyn 携带指定cookie才能访问 key为name value为chenyn
6 - Header=X-Request-Id,\d+ 请求必须含有指定的请求头X-Request-Id
7 - Method=GET 限定指定的请求方式为get请求方式
网关过滤使用 GatewayFilter Factories
1 - AddRequestHeader=User-Name, chenyn #用来给路由对象的所有请求加入指定的请求头信息
案例:
访问消费者方法:
@GetMapping("/list")
public String list(HttpServletRequest request){
String header = request.getHeader("User-Name");
System.out.println("获取请求头信息: "+header);
log.info("商品列表服务");
return "list ok当前提供服务端口:"+port;
}
测试:
2 - AddRequestParameter=color, blue #用来给路由对象的所有转发请求加入指定的请求参数
案例:
访问消费者方法:
@GetMapping("/list")
public String list(HttpServletRequest request,String color){
String header = request.getHeader("User-Name");
System.out.println("获取对应请求参数 color: "+color);
System.out.println("获取请求头信息: "+header);
log.info("商品列表服务");
return "list ok当前提供服务端口:"+port;
}
测试:
3 - PrefixPath=/product #用来给路由对象的所有转发请求的url加入指定的前缀信息
案例:
测试:
等等…
以上是springcloud提供的内置过滤器,我们也可以自定义全局过滤器,所有请求都要经过全局的filter之后再转发到后端服务
/**
* 自定义网关全局filter
*/
@Configuration
public class CustomerGlobalFilter implements GlobalFilter, Ordered {
//类似javaweb doFilter
//exchange : 交换 request response 封装了 request response
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
//httprequest对象
ServerHttpRequest request = exchange.getRequest();
//httpresponse对象
ServerHttpResponse response = exchange.getResponse();
System.out.println("经过全局Filter处理.......");
Mono<Void> filter = chain.filter(exchange);//放心filter继续向后执行
System.out.println("响应回来Filter处理......");
return filter;
}
//order 排序 int数字:用来指定filter执行顺序 默认顺序按照自然数字进行排序 -1 在所有filter执行之前执行
@Override
public int getOrder() {
return -1;
}
}
测试: