SpringCloud系列教程(八):服务网关Gateway

ops/2025/3/4 4:23:10/

上一节演示了SpringCloud的网关服务,从application.yml里我们可以看到gateway的主要配置有id,uri和predicates,其中predicates的配置提供了我们一些网关逻辑,可以帮助我们进行路由规则的匹配,如果匹配不上一般就会出现404,这时候我们就要仔细检查配置是否出现了错误,所以称之为路由断言,断言就是匹配不上就报错。路由断言是通过各个断言工厂实现的,因此在SpringCloud的源码里我们能发现很多的断言工厂类,所以我猜SpringCloud很可能使用了设计模式里的抽象工厂模式。具体配置我们就看官方文档,不同版本也不完全一致,根据自己的需要查找对应版本的文档。我现在用的是这个版本地址:Spring Cloud Gateway

另外我们还缺少一个很重要的配置就是路由过滤器filter,它是用来对网关获取到的http请求做一些操作的,比如判断请求时间,判断请求路径等。同样过滤器也是通过多个过滤器工厂类实现的,官方文档地址:Spring Cloud Gateway

我们加一个filter,比如给nacos-client-demo的请求中加入请求头,并且在接口中获取到。

1、gateway-demo中修改application.yml文件,添加filter。

spring:main:# gateway组件中的spring-boot-starter-webflux和springboot作为web项目启动必不可少的spring-boot-starter-web出现冲突web-application-type: reactiveapplication:name: gateway-democloud:nacos:server-addr: 192.168.3.54:80username: nacospassword: nacosdiscovery:group: devopsnamespace: sitconfig:namespace: sitgroup: devopsgateway:routes:- id: nacos-client-demo #指定服务名uri: lb://nacos-client-demo #去注册中心找这个服务名predicates: #断言,匹配访问的路径- Path=/nacos-client-demo/api/**    #服务访问路径filters: # 过滤器- AddRequestHeader=headername, I am a header! # 添加请求头config:import: nacos:${spring.application.name}?refresh=true
server:port: 8888

2、修改nacos-client-demo中的call接口,加入header参数。

    @RequestMapping(value = "/call", method = RequestMethod.GET)public String call(@RequestHeader String headername) {return "I am here!";}

3、重启并debug一下,观察是否把header从网关传递给了服务。

这样就成功验证了filter的作用,官方提供给了我们很多的过滤器,能满足绝大多数功能,不过还是经常会让我去自己完成过滤器的逻辑,所以我们要能做自己的过滤器。SpringCloud提供给我们两种过滤器,一种是全局过滤器GlobalFilter,声明之后自动生效,作用于全局;另一种是GatewayFilter,只能配置到具体路由上才会生效。

1、我们先做一个全局过滤器,创建新对象MyGlobalFilter,继承两个interface分别是GlobalFilter和Ordered。

package com.mj.gateway.filter;import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;@Component
public class MyGlobalFilter implements GlobalFilter, Ordered {@Overridepublic Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {//通过exchange就能获取到web请求String path = exchange.getRequest().getURI().getPath();System.out.println("MyGlobalFilter: "+path);//放到下一个filter中return chain.filter(exchange);}//继承Ordered类,用于排序,返回order值越小优先级越高@Overridepublic int getOrder() {return 0;}
}

继承GlobalFilter这个接口就会重写一下它的filter方法,这个方法有两个参数,第一个参数就是http调用对象,从里面我们可以获取到所有的http信息,用来进行我们的逻辑判断,第二个参数是filter链,表示当前filter只是gateway中所有filter链路的一个节点而已,当我们写完逻辑后,要把当前filter扔回链路中,否则请求就中断了。

继承Ordered接口之后重写方法getOrder,表示让当前filter在所有filter链路中排第几个,返回值就是顺序,越小就越靠前,0就表示它是第一个filter。

2、启动后,调用任何一个接口,都会触发到全局连接器。

3、然后再去实现一下GatewayFilter,但是与全局构造器不同,对于GatewayFilter需要去实现的是一个工厂类,所以两种filter是不一样的,我们来创建一个新的类MyGatewayFilter。

package com.mj.gateway.filter;import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.OrderedGatewayFilter;
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;@Component
public class MyGatewayFilterFactory extends AbstractGatewayFilterFactory<Object> {@Overridepublic GatewayFilter apply(Object config) {return new OrderedGatewayFilter(new GatewayFilter() {@Overridepublic Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {//通过exchange就能获取到web请求String path = exchange.getRequest().getURI().getPath();System.out.println("MyGatewayFilter: "+path);//放到下一个filter中return chain.filter(exchange);}},1);}
}

在apply方法中返回一个OrderedGatewayFilter对象,这个对象接受一个GatewayFilter对象,然后给其排序,GatewayFilter里就简单了,和上面的全局filter一样,这里顺序设置成1,让它在全局filter之后执行。

4、由于GatewayFilter需要配置到具体路由规则里之后才会生效,所以我们要在application.yml里配置一下,这里要特别注意,我们的类名是MyGatewayFilterFactory,配置的时候Filter的名字就是My,好神奇的规则。。。。

spring:main:# gateway组件中的spring-boot-starter-webflux和springboot作为web项目启动必不可少的spring-boot-starter-web出现冲突web-application-type: reactiveapplication:name: gateway-democloud:nacos:server-addr: 192.168.3.54:80username: nacospassword: nacosdiscovery:group: devopsnamespace: sitconfig:namespace: sitgroup: devopsgateway:routes:- id: nacos-client-demo #指定服务名uri: lb://nacos-client-demo #去注册中心找这个服务名predicates: #断言,匹配访问的路径- Path=/nacos-client-demo/api/**    #服务访问路径filters: # 过滤器- AddRequestHeader=headername, I am a header! # 添加请求头- Myconfig:import: nacos:${spring.application.name}?refresh=true
server:port: 8888

5、最后测试一下call方法,并且看看两个Filter的执行顺序。

虽然两个Filter我们都实现了功能,但是呢,我们肯定发现怎么跟官方的配置不太一样呢?官方的上面带着参数,还用逗号隔开,而我们这个就孤零零的两个字母My(当然如果你在项目上一定会起一个好名字),所以我们还要加一下配置参数才行。

6、修改一下MyGatewayFilterFactory类,在里面加一个内部类Config,用来接收我们application.yml中的配置。

同时,给MyGatewayFilterFactory添加构造器,把内部类Config加到构造器中,这样就完成了MyGatewayFilterFactory和Config的融合。

配置参数可能会是多个,并且用逗号隔开,所以我们还要固定配置参数和Config中变量的关系,官方已经给我预留了一个方法叫shortcutFieldOrder,我们重写一下这个方法,把对应关系的逻辑加进去。

package com.mj.gateway.filter;import lombok.Data;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.OrderedGatewayFilter;
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;import java.util.List;@Component
public class MyGatewayFilterFactory extends AbstractGatewayFilterFactory<MyGatewayFilterFactory.Config> {@Overridepublic GatewayFilter apply(Config config) {return new OrderedGatewayFilter(new GatewayFilter() {@Overridepublic Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {//通过exchange就能获取到web请求String path = exchange.getRequest().getURI().getPath();System.out.println("MyGatewayFilter: "+path);// 读取config信息System.out.println(config.toString());//放到下一个filter中return chain.filter(exchange);}},1);}//定义Config类,用来接收配置参数@Datapublic static class Config{private String a;private String b;private String c;@Overridepublic String toString(){return getA()+"-"+getB()+"-"+getC();}}// 把Config类传入到拦截器类的构造器中,这样才能把配置参数转成Config对象,注意这时候泛型也要改成Config类public MyGatewayFilterFactory(){super(Config.class);}//规范配置参数和Config类中参数的对应顺序@Overridepublic List<String> shortcutFieldOrder() {return List.of("a","b","c");}
}

7、修改application.yml,添加三个参数。

spring:main:# gateway组件中的spring-boot-starter-webflux和springboot作为web项目启动必不可少的spring-boot-starter-web出现冲突web-application-type: reactiveapplication:name: gateway-democloud:nacos:server-addr: 192.168.3.54:80username: nacospassword: nacosdiscovery:group: devopsnamespace: sitconfig:namespace: sitgroup: devopsgateway:routes:- id: nacos-client-demo #指定服务名uri: lb://nacos-client-demo #去注册中心找这个服务名predicates: #断言,匹配访问的路径- Path=/nacos-client-demo/api/**    #服务访问路径filters: # 过滤器- AddRequestHeader=headername, I am a header! # 添加请求头- My=zhangsan,lisi,wangwuconfig:import: nacos:${spring.application.name}?refresh=true
server:port: 8888

8、重启网关服务,查看一下配置参数是否正确获取。


http://www.ppmy.cn/ops/162953.html

相关文章

如何快速的解除oracle dataguard

有些时候&#xff0c;我们为了使oracle dg的standby库另做他用&#xff0c;需要解除oracle dataguard数据同步。我本地因为standby库存储出现故障&#xff0c;导致dg存在问题&#xff0c;故需要解除。今天&#xff0c;我们通过使用部分命令&#xff0c;实现dg的快速解除。 1&a…

【压力测试】

压力测试 一、背景与现状1、引言2. 压力测试与不可忽视的α3. 制度演变&#xff1a;从公募基金到理财产品4. 行业实践仍处于早期阶段5. 理财产品压力测试的优化路径 二、压力测试介绍1. 压力测试的定义2. 压力测试的步骤 一、背景与现状 1、引言 20世纪末&#xff0c;随着世界…

【面试】Java高频面试题(2023最新版)

文章目录 一、java基础 1、JDK 和 JRE 有什么区别&#xff1f;2、 和 equals 的区别是什么&#xff1f;3、final 在 java 中有什么作用&#xff1f;4、java 中的 Math.round(-1.5) 等于多少&#xff1f;5、String 属于基础的数据类型吗&#xff1f;6、String str"i"…

【Java项目】基于Spring Boot的网上商城购物系统

【Java项目】基于Spring Boot的网上商城购物系统 技术简介&#xff1a;采用Java技术、Spring Boot框架、MySQL数据库等实现。 系统简介&#xff1a;系统实现管理员&#xff1a;首页、个人中心、用户管理、商品分类管理、商品信息管理、订单评价管理、系统管理、订单管理&#x…

LeetCode 2353. 设计食物评分系统题解

一、题目描述 本题要求设计一个食物评分系统&#xff0c;该系统需要支持以下两种操作&#xff1a; 修改系统中列出的某种食物的评分&#xff1a;可以对系统中已有的某种食物的评分进行更新。返回系统中某一类烹饪方式下评分最高的食物&#xff1a;如果存在评分相同的情况&…

springBoot统一响应类型3.1版本

前言&#xff1a; 通过实践而发现真理&#xff0c;又通过实践而证实真理和发展真理。从感性认识而能动地发展到理性认识&#xff0c;又从理性认识而能动地指导革命实践&#xff0c;改造主观世界和客观世界。实践、认识、再实践、再认识&#xff0c;这种形式&#xff0c;循环往…

C++的next_permutation函数与排列问题解法

大家好哇^ _ ^ 火星人问题&#xff08;P1088&#xff09; 一、next_permutation函数解析 1.1 基本定义与特性 next_permutation是C标准库<algorithm>中的全排列生成函数&#xff0c;其核心功能是按照字典序生成给定序列的下一个排列。函数的两种形式&#xff1a; bo…

【Git】Ubuntu 安装 Git Large File Storage(LFS)以及使用 Git LFS 下载

【Git】Ubuntu 安装 Git Large File Storage&#xff08;LFS&#xff09;以及使用 Git LFS 下载 1 安装1.1 使用脚本安装1.2 使用 packagecloud 安装 2 使用2.1 下载 1 安装 1.1 使用脚本安装 参考文档: Link 下载安装包: Link 解压安装包 tar -xzvf git-lfs-linux-amd64-v3.…