[Spring Cloud] GateWay自定义过滤器/结合Nacos服务注册中心
创始人
2024-02-10 06:24:49

✨✨个人主页:沫洺的主页

📚📚系列专栏: 📖 JavaWeb专栏📖 JavaSE专栏 📖 Java基础专栏📖vue3专栏 

                           📖MyBatis专栏📖Spring专栏📖SpringMVC专栏📖SpringBoot专栏

                           📖Docker专栏📖Reids专栏📖MQ专栏📖SpringCloud专栏     

💖💖如果文章对你有所帮助请留下三连✨✨

衔接上篇: [Spring Cloud] GateWay服务网关_沫洺的博客-CSDN博客

🍁自定义全局过滤器

官方定义全局过滤器示例

接下来仿照示例创建我们自己的全局过滤器 

需求: 进行token验证(网关可以理解为一个交换机,有request和response),将原来的request通过验证并解析,过滤后构建新的request来正常调用后方的具体接口

子模块:spring-cloud-gateway

pom添加个hutool依赖

        cn.hutoolhutool-all

application.properties

spring.cloud.gateway.routes[0].id = route1
spring.cloud.gateway.routes[0].predicates[0] = Path=/test/**
spring.cloud.gateway.routes[0].filters[0] = StripPrefix=1
spring.cloud.gateway.routes[0].uri = http://httpbin.org

解析对象UserInfo

@Data
public class UserInfo {private Integer userId;private String nickName;
}

全局过滤器 CustomGlobalFilter

@Component
public class CustomGlobalFilter implements GlobalFilter, Ordered {//密钥private static final String TOKEN_SECRET="moming123";@Beanpublic GlobalFilter customFilter(){return new CustomGlobalFilter();}@Overridepublic Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) {ServerHttpRequest request = exchange.getRequest();ServerHttpResponse response = exchange.getResponse();//获取请求头Authorization存放的JWT结构的token数据List tokenList = request.getHeaders().get("Authorization");//如果为空,报401异常if(ObjectUtil.isEmpty(tokenList)){response.setStatusCode(HttpStatus.UNAUTHORIZED);return response.setComplete();}//不为空则获取tokenString token = tokenList.get(0);boolean isTrue = false;try {//验证密钥isTrue = JWTUtil.verify(token, TOKEN_SECRET.getBytes());} catch (Exception e) {e.printStackTrace();}//不匹配报401if(isTrue==false){response.setStatusCode(HttpStatus.UNAUTHORIZED);return response.setComplete();}//解析tokenfinal JWT jwt = JWTUtil.parseToken(token);//获取JWT负载部分,转成UserInfo对象//System.out.println(jwt.getPayload().toString());UserInfo userInfo = JSONUtil.toBean(jwt.getPayloads().toString(), UserInfo.class);Integer userId = userInfo.getUserId();//将userId通过header传到后端//原来的request是只读的,需要通过mutate复制一份新的request2 并添加请求头ServerHttpRequest request2 = request.mutate().header("userId", String.valueOf(userId)).build();//可以正常调用后方的具体接口//交换机也是不能改动所以复制一份,并发送新的request2return chain.filter(exchange.mutate().request(request2).build());}@Overridepublic int getOrder() {//越小优先级越高return -1;}
}

通过启动类生成一个JWT结构的token

@SpringBootApplication
public class GatewayApp {public static void main(String[] args) {SpringApplication.run(GatewayApp.class, args);Map map = new HashMap<>();map.put("userId", 1);map.put("nickName", "moming");map.put("expire_time", System.currentTimeMillis()+1000*60*60*24*5);String token = JWTUtil.createToken(map, "moming123".getBytes());System.out.println(token);}
}

运行

eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJuaWNrTmFtZSI6Im1vbWluZyIsImV4cGlyZV90aW1lIjoxNjY5NjMxMDcxNDE4LCJ1c2VySWQiOjF9.wJqasnKRQwdB-u-pm6hzqcTlfRQwX2ioHHmROspBt7Q

token错误场景

JWT回顾:[SpringBoot-vue3]用户登录实现JWT单点登录/ThreadLocal保存用户信息_沫洺的博客-CSDN博客参考博文: JSON Web Token 入门教程

🍂自定义网关(局部)过滤器

局部过滤器是只针对某个网关(路由)去生效

全局过滤器实现的是GlobalFilter,而局部过滤器实现的是GatewayFilter

定义一个局部过滤器

需求: 呈现网关调用接口耗时

这里网关调用接口服务时是异步的,比如说网关通过某个线程1去访问a服务,访问结束后返回数据时走的又是另外一个线程2,所以是异步的

那么我们要统计耗时开始时间就不能通过线程1来统计(原因是线程1可能去调用其他服务,会设置新的开始时间,),但交换机只有一个,所以可以给交换机设置一个属性开始时间戳,交换机开始作用到调用结束就是网关调用接口的耗时

@Slf4j
public class LoggerGatewayFilter implements GatewayFilter, Ordered {@Overridepublic Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) {//开始调用//设置开始时间戳exchange.getAttributes().put("start",System.currentTimeMillis());ServerHttpRequest request = exchange.getRequest();ServerHttpResponse response = exchange.getResponse();//过滤之后then异步执行一个方法return chain.filter(exchange).then(Mono.fromRunnable(()->{//运行结束long end = System.currentTimeMillis();long start = exchange.getAttribute("start");long msTime = end - start;//获取接口String rawPath = request.getURI().getRawPath();log.info("接口:{} -> 耗时:{}",rawPath,msTime);}));}@Overridepublic int getOrder() {return -1;}
}

但是局部过滤器不能像全局过滤器那样定义完放到springioc中就可以使用,要通过工厂来将我们自定义的局部过滤器生产出来,而且既然是局部的,那必然要配置指定的网关去生效,来达到按需加载的效果

配置时有个命名规则

参考内置的局部过滤器的类的命名方式及配置的命名方式

AddRequestHeaderGatewayFilterFactory======>AddRequestHeader

AddRequestParameterGatewayFilterFactory======>AddRequestParameter

所以我们自定义时的类名要加GatewayFilterFactory,配置时用前面部分即可

比如我们自定义的LoggerGatewayFilterFactory ======>Logger

@Component
public class LoggerGatewayFilterFactory extends AbstractGatewayFilterFactory {@Overridepublic GatewayFilter apply(Object config) {return new LoggerGatewayFilter();}
} 

配置

spring.cloud.gateway.routes[0].id = route1
spring.cloud.gateway.routes[0].predicates[0] = Path=/test/**
spring.cloud.gateway.routes[0].filters[0] = StripPrefix=1
spring.cloud.gateway.routes[0].filters[1] = Logger
spring.cloud.gateway.routes[0].uri = http://httpbin.org

注释掉自定义全局过滤器相关内容,运行访问

🌾结合Nacos服务注册中心

注释掉局部过滤器相关内容

调用a服务

添加依赖

        com.alibaba.cloudspring-cloud-starter-alibaba-nacos-discovery

配置nacos

#与nacos服务注册中心结合
spring.cloud.gateway.routes[1].id = route_nacos
spring.cloud.gateway.routes[1].predicates[0] = Path=/nacos-a/**
spring.cloud.gateway.routes[1].filters[0] = StripPrefix=1
#前置过滤器
spring.cloud.gateway.routes[1].filters[1] = AddRequestHeader=name,moming
spring.cloud.gateway.routes[1].uri = lb://nacos-a

启动nacos服务器

修改子模块spring-cloud-nacos-a

@RestController
public class UserServiceController implements IUserService {@Value("${server.port}")private String port;@Overridepublic String getName(Integer id) {HttpServletRequest request = ((ServletRequestAttributes) (RequestContextHolder.currentRequestAttributes())).getRequest();String name = request.getHeader("name");return StrUtil.format("nacos a({}) header:{} 返回的id: {}" ,this.port,name,id);}@Overridepublic Integer getAmount(Integer id) {return id*100;}@Overridepublic String getSleep(Integer time) {ThreadUtil.sleep(time*1000);return StrUtil.format("nacos a({}) 睡眠了 {} 秒",this.port ,time);}
}

打包运行a服务

 准备工作做完,直接运行访问

 在启动一个a服务

访问

 

相关内容

热门资讯

猫咪吃了塑料袋怎么办 猫咪误食... 你知道吗?塑料袋放久了会长猫哦!要说猫咪对塑料袋的喜爱程度完完全全可以媲美纸箱家里只要一有塑料袋的响...
demo什么意思 demo版本... 618快到了,各位的小金库大概也在准备开闸放水了吧。没有小金库的,也该向老婆撒娇卖萌服个软了,一切只...
世界上最漂亮的人 世界上最漂亮... 此前在某网上,选出了全球265万颜值姣好的女性。从这些数量庞大的女性群体中,人们投票选出了心目中最美...
埃菲尔铁塔在哪 中国仿建埃菲尔... 2019年4月26日,广西南宁市,街头惊现一座巨型山寨版埃菲尔铁塔,高约20米,白色塔身,造型逼真,...
苗族的传统节日 贵州苗族节日有... 【岜沙苗族芦笙节】岜沙,苗语叫“分送”,距从江县城7.5公里,是世界上最崇拜树木并以树为神的枪手部落...
北京的名胜古迹 北京最著名的景... 北京从元代开始,逐渐走上帝国首都的道路,先是成为大辽朝五大首都之一的南京城,随着金灭辽,金代从海陵王...
应用未安装解决办法 平板应用未... ---IT小技术,每天Get一个小技能!一、前言描述苹果IPad2居然不能安装怎么办?与此IPad不...
脚上的穴位图 脚面经络图对应的... 人体穴位作用图解大全更清晰直观的标注了各个人体穴位的作用,包括头部穴位图、胸部穴位图、背部穴位图、胳...
长白山自助游攻略 吉林长白山游... 昨天介绍了西坡的景点详细请看链接:一个人的旅行,据说能看到长白山天池全凭运气,您的运气如何?今日介绍...
猫咪吃了塑料袋怎么办 猫咪误食... 你知道吗?塑料袋放久了会长猫哦!要说猫咪对塑料袋的喜爱程度完完全全可以媲美纸箱家里只要一有塑料袋的响...
demo什么意思 demo版本... 618快到了,各位的小金库大概也在准备开闸放水了吧。没有小金库的,也该向老婆撒娇卖萌服个软了,一切只...
世界上最漂亮的人 世界上最漂亮... 此前在某网上,选出了全球265万颜值姣好的女性。从这些数量庞大的女性群体中,人们投票选出了心目中最美...
埃菲尔铁塔在哪 中国仿建埃菲尔... 2019年4月26日,广西南宁市,街头惊现一座巨型山寨版埃菲尔铁塔,高约20米,白色塔身,造型逼真,...