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;
- }
- }
-
测试: