[Spring Cloud] GateWay自定义过滤器/结合Nacos服务注册中心

news2024/11/19 10:19:10

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

📚📚系列专栏: 📖 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依赖

        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
        </dependency>

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";
    @Bean
    public GlobalFilter customFilter(){
        return new CustomGlobalFilter();
    }
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        ServerHttpResponse response = exchange.getResponse();
        //获取请求头Authorization存放的JWT结构的token数据
        List<String> tokenList = request.getHeaders().get("Authorization");
        //如果为空,报401异常
        if(ObjectUtil.isEmpty(tokenList)){
            response.setStatusCode(HttpStatus.UNAUTHORIZED);
            return response.setComplete();
        }
        //不为空则获取token
        String token = tokenList.get(0);
        boolean isTrue = false;
        try {
            //验证密钥
            isTrue = JWTUtil.verify(token, TOKEN_SECRET.getBytes());
        } catch (Exception e) {
            e.printStackTrace();
        }
        //不匹配报401
        if(isTrue==false){
            response.setStatusCode(HttpStatus.UNAUTHORIZED);
            return response.setComplete();
        }
        //解析token
        final 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();

        //可以正常调用后方的具体接口
        //交换机也是不能改动所以复制一份,并发送新的request2
        return chain.filter(exchange.mutate().request(request2).build());
    }

    @Override
    public int getOrder() {
        //越小优先级越高
        return -1;
    }
}

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

@SpringBootApplication
public class GatewayApp {

    public static void main(String[] args) {
        SpringApplication.run(GatewayApp.class, args);

        Map<String,Object> 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 {

    @Override
    public Mono<Void> 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);
        }));
    }

    @Override
    public int getOrder() {
        return -1;
    }
}

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

配置时有个命名规则

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

AddRequestHeaderGatewayFilterFactory======>AddRequestHeader

AddRequestParameterGatewayFilterFactory======>AddRequestParameter

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

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

@Component
public class LoggerGatewayFilterFactory extends AbstractGatewayFilterFactory<Object> {
    @Override
    public 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服务

添加依赖

        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
            <!--<version>2.2.1.RELEASE</version>-->
        </dependency>

配置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;
    @Override
    public 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);
    }
    @Override
    public Integer getAmount(Integer id) {
        return id*100;
    }
    @Override
    public String getSleep(Integer time) {
        ThreadUtil.sleep(time*1000);
        return StrUtil.format("nacos a({}) 睡眠了 {} 秒",this.port ,time);
    }
}

打包运行a服务

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

 在启动一个a服务

访问

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/29494.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

DocuWare Workflow Manager(工作流管理器)

DocuWare Workflow Manager 公司是按流程运转的。销售、人力资源、财务等部门需要流畅、可靠的信息传输&#xff0c;以便在正确的时间做出正确的决策。订单管理、员工入职和发票审批等流程可以根据您的精确需求进行设计和自动化&#xff0c;避免时间浪费。 适用于复杂业务的简…

Mysql数据库相关面试题

1.关系型和非关系型数据库的区别是什么? 关系型和非关系型数据库的主要差异是数据存储的方式,关系型数据库天然就是表格存储,因此存储在数据表的行和列中,数据表可以彼此关联协作存储,很容易提取数据. 优点: 易于维护:都是使用表结构,格式一致,使用方便:sql语言通用,可以用于复…

MyBatis逆向工程和分页插件

1、分页插件 MyBatis 通过提供插件机制&#xff0c;让我们可以根据自己的需要去增强MyBatis 的功能。需要注意的是&#xff0c;如果没有完全理解MyBatis 的运行原理和插件的工作方式&#xff0c;最好不要使用插件&#xff0c; 因为它会改变系底层的工作逻辑&#xff0c;给系统带…

2022年全国职业院校技能大赛:网络系统管理项目-模块B--Windows样题7

初始化环境1.默认账号及默认密码 Username: Administrator Password: ChinaSkill22! Username: demo Password: ChinaSkill22! 注:若非特别指定,所有账号的密码均为 ChinaSkill22! 项目任务描述你作为技术工程师,被指派去构建一个公司的内部网络,要为员工提供便捷、安…

超算云平台在线功能Q-Flow、Q-Studio V2.1版本升级,web端在线建模+DFT计算

建模DFT计算还可以这么玩&#xff1f; Q-Flow&#xff08;在线可视化提交任务功能&#xff09;以及 Q-Studio&#xff08;在线建模功能&#xff09;依托Mcloud平台免费向用户开放使用。告别Linux编辑代码提交任务的模式&#xff0c;Q-Flow可在浏览器里通过拖拽图形化的第一性原…

【第06节】Selenium4 JavaScript 处理场景实战(Python Web自动化测试)

Selenium 4 【01-06节】主讲元素定位&#xff0c;处理一些特殊场景的方法与实战已经全部写完。文章所有素材来自互联网&#xff0c;如果文章有侵权处&#xff0c;请联系作者。 文章目录1、Selenium4 自动化 JavaScript 场景实战1.1 使用 JavaScript 处理富文本1.2 使用 JavaScr…

Linux——网络编程总结性学习

什么是ISP&#xff1f; 网络业务提供商_百度百科 计算机网络有哪些分类方式,计算机网络有哪些分类&#xff1f;_陈泽杜的博客-CSDN博客 路由器_百度百科 目前实际的网络分层是TCP/IP四层协议 当我们浏览⽹站找到想要下载的⽂件以后&#xff0c;找到相应的接⼝点击下载就好了。…

新形势下安全风险评估实践

​ 随着安全内涵的不断扩充和发展&#xff0c;风险评估作为安全管理的重点&#xff0c;内容以及方法都与时俱进的得到了发展和丰富&#xff0c;本文将介绍新形势下风险评估的特点和实践心得&#xff0c;以供参考。 一、新形势下安全风险评估特点 首先是内外部形势和要求的变…

Docker入门教程(详细)

目录 一、Docker概述 1.1 Docker 为什么出现&#xff1f; 1.2 Dorker历史 1.3 能做什么 虚拟机技术&#xff1a;&#xff08;通过 软件 模拟的具有完整 硬件 系统功能的、运行在一个完全 隔离 环境中的完整 计算机系统&#xff09; 容器化技术&#xff1a;&#xff08;容…

【JAVA高级】——玩转JDBC中的三层架构

✅作者简介&#xff1a;热爱国学的Java后端开发者&#xff0c;修心和技术同步精进。 &#x1f34e;个人主页&#xff1a;Java Fans的博客 &#x1f34a;个人信条&#xff1a;不迁怒&#xff0c;不贰过。小知识&#xff0c;大智慧。 &#x1f49e;当前专栏&#xff1a;Java案例分…

Oracle SQL执行计划操作(8)——视图与集合相关操作

8. 视图相关操作 该类操作与包含视图的SQL语句相关。当SQL语句被硬解析时,如果SQL语句中的视图未被合并,则根据不同的具体场景,如下各操作可能会出现于相关SQL语句的执行计划。 1)VIEW 创建数据的一个中间视图,一般分为系统视图和用户视图。优化器在为SQL语句生成执行计…

iOS上架流程详细版本

苹果上架审核周期长一直是困扰用户的一大问题&#xff0c;这次把我自己上架的经历分享给大家&#xff0c;避免大家入坑。 上架总流程&#xff1a; 创建开发者账号 借助辅助工具appuploader创建证书&#xff0c;描述文件 iTunes connect创建App 打包IPA上传App Store等待审…

Kubernetes(k8s)CNI(flannel)网络模型原理

一、概述 Kubernetes 采用的是基于扁平地址空间的、非NAT的网络模型&#xff0c;每个Pod有自己唯一的IP地址。网络是由CNI(container network interface)插件建立的&#xff0c;而非K8S本身。 二、常见的几种CNI插件介绍 为了使容器之间的通信更加方便&#xff0c;Google 和 Co…

计算机网络面试大总结

本文分文五大部分&#xff0c;第一部分总纲说明计算机网络层次划分的三种模型&#xff0c;一到四部分以TCP/IP协议模型作为划分标准&#xff0c;分别说明各层作用和最常见的面试题&#xff0c;最后总结网络综合面试题&#xff0c;历时六天全文一千字。 其他经典面试题参考程序员…

虹科校园大使招募令

虹科校园大使招募令 我们正式邀请你成为虹科校内明星代言人&#xff01; 近距离接触技术大牛工作领域 来自人力总监的职业发展指导 官方校园大使认证证书 走内部通道提前斩获校招offer 你将成为 校园品牌首席推广师 赋予你自主“DIY”的权利&#xff0c;与校招负责人一起…

损失函数——机器学习

目录 一、实验内容 二、实验过程 1、算法思想 2、算法原理 3、算法分析 三、源程序代码 四、运行结果分析 五、实验总结 一、实验内容 理解损失函数的基本概念&#xff1b;理解并掌握均方差损失函数的原理&#xff0c;算法实现及代码测试分析&#xff1b;理解并掌握交叉…

【linux】linux实操篇之权限管理

14天学习训练营导师课程&#xff1a; 互联网老辛《 符合学习规律的超详细linux实战快速入门》 目录前言权限的基本介绍rwx权限详解更改文件属性1、chgrp&#xff1a;更改文件属组2、chown&#xff1a;更改文件属主&#xff0c;也可以同时更改文件属组3、chmod&#xff1a;更改文…

帷幄前沿茶话丨如何发起一场直播间运营变革?

打开抖音&#xff0c;各种各样的带货模式都有。吃播的、喊麦的、跳舞的、说相声的&#xff0c;各种表现形式都可以是带货的手段。 但实际效果如何复盘&#xff1f;一旦感性的带货模式回归到理性分析&#xff0c;问题就没那么简单了。 电商的关键衡量指标是 GMV。直播带货中&…

[附源码]java毕业设计学院竞赛管理信息系统

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

RabbitMQ【基本使用】

目录 消息队列 1. Message queue 释义 1.1 问题思考 ? 1.2 存在问题 1.3 优化方案 1.4 案例分析 1.5 带来的好处 1.6 消息队列特点 1.7 Email邮件案例分析 2. 消息队列相关 2.1 AMQP 3. Docker安装部署RabbitMQ 4. springboot连接配置 4.1 RabbitMQ 配置账号…