微服务网关Gateway(下)

CSDN 的小伙伴们,大家好呀,我是苍何。

这篇文章我们继续来说下我们项目中用到的微服务网关 Gateway 的技术点。主要涵盖过滤器,限流处理以及黑白名单配置。

过滤器

网关中的过滤器,有点类似 SpringMVC 里面的拦截器 Interceptor 以及 Servlet 的过滤器,其中「pre」 和「post」分别会在请求被执行钱调用和被执行后调用,用来修改请求和响应信息。

过滤器也是面试中最常问的知识点,比如记录接口调用市场统计、限流、黑白名单等。

按照类型分的话,过滤器分为全局默认过滤器、单一内置过滤器和自定义过滤器。

全局过滤器

全局过滤器作用于所有的路由,不需要单独配置,我们可以用它来实现很多统一化处理的业务需求,比如权限认证,IP 访问限制等等。目前网关统一鉴权 AuthFilter.java 就是采用的全局过滤器。
单独定义只需要实现 GlobalFilter, Ordered 这两个接口就可以了。

/**
 * 网关鉴权
 *
 * @author canghe
 */
@Component
public class AuthFilter implements GlobalFilter, Ordered {
    private static final Logger log = LoggerFactory.getLogger(AuthFilter.class);

    // 排除过滤的 uri 地址,nacos自行添加
    @Autowired
    private IgnoreWhiteProperties ignoreWhite;

    @Autowired
    private RedisService redisService;


    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        ServerHttpRequest.Builder mutate = request.mutate();

        String url = request.getURI().getPath();
        // 跳过不需要验证的路径
        if (StringUtils.matches(url, ignoreWhite.getWhites())) {
            return chain.filter(exchange);
        }
        String token = getToken(request);
        if (StringUtils.isEmpty(token)) {
            return unauthorizedResponse(exchange, "令牌不能为空");
        }
        Claims claims = JwtUtils.parseToken(token);
        if (claims == null) {
            return unauthorizedResponse(exchange, "令牌已过期或验证不正确!");
        }
        String userkey = JwtUtils.getUserKey(claims);
        boolean islogin = redisService.hasKey(getTokenKey(userkey));
        if (!islogin) {
            return unauthorizedResponse(exchange, "登录状态已过期");
        }
        String userid = JwtUtils.getUserId(claims);
        String username = JwtUtils.getUserName(claims);
        if (StringUtils.isEmpty(userid) || StringUtils.isEmpty(username)) {
            return unauthorizedResponse(exchange, "令牌验证失败");
        }

        // 设置用户信息到请求
        addHeader(mutate, SecurityConstants.USER_KEY, userkey);
        addHeader(mutate, SecurityConstants.DETAILS_USER_ID, userid);
        addHeader(mutate, SecurityConstants.DETAILS_USERNAME, username);
        // 内部请求来源参数清除(防止网关携带内部请求标识,造成系统安全风险)
        removeHeader(mutate, SecurityConstants.FROM_SOURCE);
        return chain.filter(exchange.mutate().request(mutate.build()).build());
    }
}

单一内置过滤器

单一内置过滤器也可以称为网关过滤器,这种过滤器主要是作用于单一路由或者某个路由。

单一内置过滤器-官网

有以下几种常见的单一过滤器。

  • 指定请求头内容

可以过滤掉指定请求头的路径,比如我希望此方法只允许请求头中带有“X-Request-pmhub”或者“X-Request-pmhub2”的请求。


/**
 * @author canghe
 * @description GatewayFilter
 * @create 2024-05-27-06:55
 */
public class GatewayFilter {
    @GetMapping(value = "/pay/gateway/filter")
    public AjaxResult getGatewayFilter(HttpServletRequest request)
    {
        String result = "";
        Enumeration<String> headers = request.getHeaderNames();
        while(headers.hasMoreElements())
        {
            String headName = headers.nextElement();
            String headValue = request.getHeader(headName);
            System.out.println("请求头名: " + headName +"\t\t\t"+"请求头值: " + headValue);
            if(headName.equalsIgnoreCase("X-Request-pmhub")
                    || headName.equalsIgnoreCase("X-Request-pmhub2")) {
                result = result+headName + "\t " + headValue +" ";
            }
        }
        return AjaxResult.success("getGatewayFilter 过滤器 test: "+result+" \t "+ DateUtil.now());
    }
}

那就可以在配置中做如下配置即可:

 predicates:
        - Path=/auth/gateway/info/**              # 断言,路径相匹配的进行路由

        - id: pmhub_routh3 #pay_routh3
          uri: lb://cloud-pmhub-service                #匹配后提供服务的路由地址
          predicates:
            - Path=/pay/gateway/filter/**              # 断言,路径相匹配的进行路由
          filters:
            - AddRequestHeader=X-Request-pmhub,pmhubValue1  # 请求头kv,若一头含有多参则重写一行设置
            - AddRequestHeader=X-Request-pmhub2,pmhubValue2

那么方法就能针对特定请求头内容做逻辑处理就好了,这样针对于请求头中的内容可以做过滤,可用于其他鉴权等情况。

  • 指定请求参数

对于特定请求参数进行过滤,只有带有该参数的请求才可执行逻辑。

  predicates:
            - Path=/auth/gateway/filter/**              # 断言,路径相匹配的进行路由
          filters:
            - AddRequestParameter=customerId,9527001 # 新增请求参数Parameter:k ,v
            - RemoveRequestParameter=customerName   # 删除url请求参数customerName,你传递过来也是null

很多朋友在问新项目的进展,这里我统一放一下彩蛋:

我们已经完成了所有代码编写,目前正在文档和教程完善中,提供了单体和微服务版本,并且提供了一套由单体应用改造为微服务的可落地方法论,并能帮助同学们快速掌握分布式微服务项目的核心知识,主要技术栈有:SpringCloud、SpringCloud Alibaba、Spring Boot Actuator、Skywalking、Sentinel 熔断降级、Seata 分布式事务等,

  • 指定回应头

可以添加响应头信息,这样对于下游系统或者 web 可以做相应的逻辑处理和鉴权。这个过滤器应用场景可以无限发挥你的想象。

  predicates:
            - Path=/auth/gateway/filter/**              # 断言,路径相匹配的进行路由
          filters:
            - AddResponseHeader=X-Response-pmhub, BlueResponse # 新增请求参数X-Response-pmhub并设值为BlueResponse
            
  • 指定前缀和路径

很好理解,就是能对前缀和路径进行过滤,还可以进行路径重定向,配置如下:

  predicates:
            - Path=/auth/gateway/filter/**              # 断言,路径相匹配的进行路由
          filters:
            - PrefixPath=/pmhub # http://localhost:6880/pmhub/gateway/filter
            - RedirectTo=302, https://laigeoffer.cn/ # 访问http://localhost:6880/pmhub/gateway/filter跳转到https://laigeoffer.cn/
            

自定义过滤器

经典面试题:如何统计接口调用耗时情况,说说设计思路?

这里我们就可以利用 gateway 的自定义过滤器功能来实现该功能。需要自定义全局 filter,只需要实现 GlobalFilter, Ordered 这两个接口,并在 filter 方法中进行接口访问耗时情况统计即可,比如这个 demo:

return chain.filter(exchange).then(Mono.fromRunnable(()->{
    Long beginVisitTime = exchange.getAttribute(BEGIN_VISIT_TIME);
    if (beginVisitTime != null){
        log.info("访问接口主机: " + exchange.getRequest().getURI().getHost());
        log.info("访问接口端口: " + exchange.getRequest().getURI().getPort());
        log.info("访问接口URL: " + exchange.getRequest().getURI().getPath());
        log.info("访问接口URL参数: " + exchange.getRequest().getURI().getRawQuery());
        log.info("访问接口时长: " + (System.currentTimeMillis() - beginVisitTime) + "ms");
        log.info("我是美丽分割线: ###################################################");
        System.out.println();
    }
}));

实际上在 pmhub 中统计接口调用耗时情况只需要通过以下一行代码即可:

//先记录下访问接口的开始时间
        exchange.getAttributes().put(BEGIN_VISIT_TIME, System.currentTimeMillis());

这个点大家完全可以体现在简历中,可以大大加分哦。

限流配置

限流,顾名思义,就是对流量进行限制。通过实施限流措施,我们可以有效地管理系统的每秒请求数(QPS),从而实现对系统的保护。

常见的限流算法包括:计数器算法漏桶算法(Leaky Bucket)、以及令牌桶算法(Token Bucket)。

在Spring Cloud Gateway 中,官方提供了RequestRateLimiterGatewayFilterFactory 过滤器工厂,通过结合 Redis和 Lua 脚本,实现了基于令牌桶的限流方式。

  1. 添加依赖
<!-- spring data redis reactive 依赖 -->
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-data-redis-reactive</artifactId>
</dependency>
  1. 限流规则,根据URI限流
spring:
  redis:
    host: localhost
    port: 6379
    password: 
  cloud:
    gateway:
      routes:
        # 系统模块
        - id: pmhub-system
          uri: lb://pmhub-system
          predicates:
            - Path=/system/**
          filters:
            - StripPrefix=1
            - name: RequestRateLimiter
              args:
                redis-rate-limiter.replenishRate: 1 # 令牌桶每秒填充速率
                redis-rate-limiter.burstCapacity: 2 # 令牌桶总容量
                key-resolver: "#{@pathKeyResolver}" # 使用 SpEL 表达式按名称引用 bean

::: tip
StripPrefix=1配置,表示网关转发到业务模块时候会自动截取前缀。这个配置需要视情况而定
:::

  1. 编写URI限流规则配置类
/**
 * 限流规则配置类
 */
@Configuration
public class KeyResolverConfiguration
{
    @Bean
    public KeyResolver pathKeyResolver()
    {
        return exchange -> Mono.just(exchange.getRequest().getURI().getPath());
    }
}
  1. 测试服务验证限流

启动网关服务 PmHubGatewayApplication.java 和系统服务PmHubSystemApplication.java。

因为网关服务有认证鉴权,可以在 gateway 配置中设置一下白名单/system/**在进行测试,多次请求会发现返回 HTTP ERROR 429,同时在 redis 中会操作两个 key,表示限流成功。

request_rate_limiter.{xxx}.timestamp
request_rate_limiter.{xxx}.tokens

也可以根据其他限流规则来配置,如参数限流,IP限流,配置如下:

//参数限流
@Bean
public KeyResolver parameterKeyResolver()
{
    return exchange -> Mono.just(exchange.getRequest().getQueryParams().getFirst("userId"));
}

// ip限流

@Bean
public KeyResolver ipKeyResolver()
{
	return exchange -> Mono.just(exchange.getRequest().getRemoteAddress().getHostName());
}

黑名单配置

顾名思义,黑名单就是那些被禁止访问的URL。为了实现这一功能,可以创建自定义过滤器 BlackListUrlFilter,并配置黑名单地址列表blacklistUrl。当然,如果有其他需求,还可以实现自定义规则的过滤器来满足特定的过滤要求。

pmhub 中黑名单过滤器配置:

/**
 * 黑名单过滤器
 *
 * @author canghe
 */
@Component
public class BlackListUrlFilter extends AbstractGatewayFilterFactory<BlackListUrlFilter.Config>
{
    @Override
    public GatewayFilter apply(Config config)
    {
        return (exchange, chain) -> {

            String url = exchange.getRequest().getURI().getPath();
            if (config.matchBlacklist(url))
            {
                return ServletUtils.webFluxResponseWriter(exchange.getResponse(), "请求地址不允许访问");
            }

            return chain.filter(exchange);
        };
    }

    public BlackListUrlFilter()
    {
        super(Config.class);
    }

    public static class Config
    {
        private List<String> blacklistUrl;

        private List<Pattern> blacklistUrlPattern = new ArrayList<>();

        public boolean matchBlacklist(String url)
        {
            return !blacklistUrlPattern.isEmpty() && blacklistUrlPattern.stream().anyMatch(p -> p.matcher(url).find());
        }

        public List<String> getBlacklistUrl()
        {
            return blacklistUrl;
        }

        public void setBlacklistUrl(List<String> blacklistUrl)
        {
            this.blacklistUrl = blacklistUrl;
            this.blacklistUrlPattern.clear();
            this.blacklistUrl.forEach(url -> {
                this.blacklistUrlPattern.add(Pattern.compile(url.replaceAll("\\*\\*", "(.*?)"), Pattern.CASE_INSENSITIVE));
            });
        }
    }

}

以后只要是看哪个 URL 不爽,就直接拉进很名单即可。

spring:
  cloud:
    gateway:
      routes:
        # 系统模块
        - id: pmhub-system
          uri: lb://pmhub-system
          predicates:
            - Path=/system/**
          filters:
            - StripPrefix=0
            - name: BlackListUrlFilter
              args:
                blacklistUrl:
                - /user/list

白名单配置

顾名思义,就是允许访问的地址。且无需登录就能访问。比如登录、注册接口,以及其他的不需要网关做鉴权的接口,都可以放在白名单里面。爱他,就把她放进来吧\(^ ^)/,在 ignore 中设置 whites,表示允许匿名访问。

在全局过滤器中添加以下逻辑即可。

// 跳过不需要验证的路径
if (StringUtils.matches(url, ignoreWhite.getWhites())) {
    return chain.filter(exchange);
}
# 不校验白名单
ignore:
  whites:
    - /auth/logout
    - /auth/login

以上是关于网关的过滤器以及常用功能的介绍,结合实际项目使用,理解这些概念和使用方法并不是什么难事,而且用会还可以写在简历上去和面试官吹逼,简直不要太爽,来个 offer 指日可待。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

面试官:什么是Redis持久化—>AOF持久化

&#x1f604;作者简介&#xff1a; 小曾同学.com,一个致力于测试开发的博主⛽️&#xff0c;主要职责&#xff1a;测试开发、CI/CD 如果文章知识点有错误的地方&#xff0c;还请大家指正&#xff0c;让我们一起学习&#xff0c;一起进步。 &#x1f60a; 座右铭&#xff1a;不…

Python | Leetcode Python题解之第130题被围绕的区域

题目&#xff1a; 题解&#xff1a; class Solution:def solve(self, board: List[List[str]]) -> None:if not board:returnn, m len(board), len(board[0])que collections.deque()for i in range(n):if board[i][0] "O":que.append((i, 0))board[i][0] &q…

C语言 | Leetcode C语言题解之第129题求根节点到叶节点数字之和

题目&#xff1a; 题解&#xff1a; int sumNumbers(struct TreeNode* root) {if (root NULL) {return 0;}int sum 0;struct TreeNode* nodeQueue[2000];int numQueue[2000];int leftQueue 0, rightQueue 0;nodeQueue[rightQueue] root;numQueue[rightQueue] root->v…

MPEG-TS 封装格式详解

MPEG-TS 封装格式详解 MPEG-TS 封装格式详解简介基本概念TS 文件格式PSI&#xff08;Program Specific Information&#xff09;节目关联表&#xff08;PAT&#xff0c;Program Association Table&#xff09;节目映射表&#xff08;PMT&#xff0c;Program Map Table&#xff…

探索k8s集群的配置资源(secret和configmap)

目录 ConfigMap ConfigMap&#xff08;主要是将配置目录或者文件挂载到k8s里面使用&#xff09; 与Secret类似&#xff0c;区别在于ConfigMap保存的是不需要加密配置的信息。&#xff08;例如&#xff1a;配置文件&#xff09; ConfigMap 功能在 Kubernetes1.2 版本中引入&…

算法 java 排序和查找

排序和查找 冒泡排序&#xff08;稳定&#xff09;选择排序&#xff08;不稳定&#xff09;插入排序&#xff08;稳定&#xff09;希尔排序&#xff08;不稳定&#xff09;归并排序&#xff08;稳定&#xff09;快速排序&#xff08;不稳定&#xff09;堆排序计数排序桶排序基数…

Scikit-Learn随机森林分类

Scikit-Learn随机森林分类 1、随机森林分类1.1、随机森林分类概述1.2、随机森林分类的优缺点2、Scikit-Learn随机森林分类2.1、Scikit-Learn随机森林分类API2.2、Scikit-Learn随机森林分类初体验(葡萄酒分类)2.3、Scikit-Learn随机森林分类实践(鸢尾花分类)2.4、参数调优与…

undefined symbol: _ZN3c104impl8GPUTrace13gpu mmcv

这里写自定义目录标题 ImportError: //python3.8/site-packages/mmcv/_ext.cpython-38-x86_64-linux-gnu.so: undefined symbol: _ZN3c104impl8GPUTrace13gpuTraceStateEERROR conda.cli.main_run:execute(49): 这样的问题往往都是版本不匹配导致的 pytorch的版本&#xff0c;m…

为Android组件化项目搭建Maven私服

概览 文章目录 概览前言搭建 maven 私服服务器环境jdk安装配置nexus安装配置管理创建存储点、仓库 项目中使用 maven 私服上传 module 到仓库自动发布 module手动上传单个aar包 引用仓库中的 modulebuild.gradle引入远程module FAQ开发阶段有些module用远程依赖&#xff0c;有些…

构建大型语言模型(LLM)产品的实战指南

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…

#13前端后花园周刊-10个现代 Node.js 运行时新特性、Nextjs15、Astro4.9、CSS压缩

⚡️行业动态 JavaScript 的创建者 Brendan Eich 在 Twitter/X 上出现&#xff0c;反驳了 JS 是“最邋遢的”的说法&#xff0c;称其只有 50% 。 &#x1f4c6;发布 Next.js 15 RC 流行的 React 元框架已经准备好迎接一个主要的新版本&#xff0c;它有一个 RC&#xff0c;让…

YOLOv9改进策略 | 添加注意力篇 | 利用YOLOv10提出的PSA注意力机制助力YOLOv9有效涨点(附代码 + 详细修改教程)

一、本文介绍 本文给大家带来的改进机制是YOLOv10提出的PSA注意力机制&#xff0c;自注意力在各种视觉任务中得到了广泛应用&#xff0c;因为它具有显著的全局建模能力。然而&#xff0c;自注意力机制表现出较高的计算复杂度和内存占用。为了解决这个问题&#xff0c;鉴于注意…

群体优化算法---蝙蝠优化算法分类Iris数据集

介绍 蝙蝠算法&#xff08;Bat Algorithm, BA&#xff09;是一种基于蝙蝠回声定位行为的优化算法。要将蝙蝠算法应用于分类问题&#xff0c;可以通过将蝙蝠算法用于优化分类器的参数&#xff0c;图像分割等 本文示例 我们使用一个经典的分类数据集&#xff0c;如Iris数据集&…

基于深度学习的CT影像肺癌检测识别

温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长 QQ 名片 :) 1. 项目简介 肺癌是全球范围内导致癌症死亡的主要原因之一&#xff0c;早期检测和诊断对于提高患者生存率至关重要。随着深度学习技术的迅猛发展&#xff0c;基于CT影像的肺癌检测识别成为了研究热点。本文介绍…

Spire.PDF for .NET【文档操作】演示:在 C# 中向 PDF 文件添加图层

Spire.PDF 完美支持将多页 PDF 拆分为单页。但是&#xff0c;更常见的情况是&#xff0c;您可能希望提取选定的页面范围并保存为新的 PDF 文档。在本文中&#xff0c;您将学习如何通过 Spire.PDF 在 C#、VB.NET 中根据页面范围拆分 PDF 文件。 Spire.PDF for .NET 是一款独立 …

wireshark 二次开发

一、 Windows 准备 1、源代码下载 Git&#xff1a;https://github.com/wireshark/wireshark 2、 准备Visual C 要编译wireshark&#xff0c;开发电脑上应该安装了Visual Studio并包括了Visual C&#xff0c;请至少安装Visual Studio 2010以减少不必要的麻烦。 visual studio …

英码科技推出鸿蒙边缘计算盒子:提升国产化水平,增强AI应用效能,保障数据安全

当前&#xff0c;随着国产化替代趋势的加强&#xff0c;鸿蒙系统Harmony OS也日趋成熟和完善&#xff0c;各行各业都在积极拥抱鸿蒙&#xff1b;那么&#xff0c;边缘计算要加快实现全面国产化&#xff0c;基于鸿蒙系统开发AI应用势在必行。 关于鸿蒙系统及其优势 鸿蒙系统是华…

友顺科技(UTC)分立器件与集成IC产品选型和应用

友顺科技股份有限公司成立于1990年&#xff0c;是全球领先的集成电路与功率半导体厂商 ,集团总部位于台北&#xff0c;生产基地位于福州、厦门。 友顺科技具有完整模拟组件产品线&#xff0c;其中类比IC涵盖各种稳压器、PWM控制IC, 放大器、比较器、逻辑IC、Voltage Translato…

Pulsar 社区周报 | No.2024-05-30 | BIGO 百页小册《Apache Pulsar 调优指南》

“ 各位热爱 Pulsar 的小伙伴们&#xff0c;Pulsar 社区周报更新啦&#xff01;这里将记录 Pulsar 社区每周的重要更新&#xff0c;每周发布。 ” BIGO 百页小册《Apache Pulsar 调优指南》 Hi&#xff0c;Apache Pulsar 社区的小伙伴们&#xff0c;社区 2024 上半年度的有奖问…

VB.net实战(VSTO):Excel插件设计Ribbon界面

1. 新建Ribbon 1.1 开发环境 Visual Studio 2022 1.2 解决方案资源管理器中右击My Project 1.3 添加》新建项 1.4 office/SharePoint》功能区(可视化设计器)&#xff0c;双击 2.调出工具箱 Visual Studio 2022》视图》工具箱 3.设计界面 3.1 添加功能区选项卡 3.2拖动Group…