SpringCloudGateway网关中各个过滤器的作用与介绍

news2024/11/20 3:19:49

文章目录

  • RemoveCachedBodyFilter
  • AdaptCachedBodyGlobalFilter
  • NettyWriteResponseFilter
  • ForwardPathFilter
  • RouteToRequestUrlFilter
  • WebSocketRoutingFilter
  • NettyRoutingFilter
  • ForwardRoutingFilter
  • DispatcherHandler 是什么?
  • ⭐如何确定最后的路由路径?
  • 下文:如何根据过滤器链设计一个自己的数字签名?如何对URL上的参数进行加密解密来保证数据安全性?

在我搭建的微服务项目中,网关是非常重要的一环,起到了请求过滤和拦截的。
我最近需要在网关实现URL请求参数加密以及数字签名检验请求参数是否被篡改等功能,所以最近着手开始研究起了网关。
首先最重要的就是先配置一个自己的过滤器,来完成验证。
然后就在设计的过程中遇到了一些问题,比如请求转发,请求request修改失败等问题。
所以学习一下源码,了解过滤器链就变得比较重要了。
这篇文章主要记录的是我对Gateway网关中比较重要的几个过滤器的作用的理解。
我的springcloudgateway的版本是3.1.4,还算可以,如下是filter包下面的过滤器。
在这里插入图片描述
下图是我的gateway的配置,以及我自定义的几个全局过滤器。
在这里插入图片描述

RemoveCachedBodyFilter

AdaptCachedBodyGlobalFilter

AdaptCachedBodyGlobalFilter是一个全局过滤器,用于在请求到达网关时对请求进行处理。它的作用是将请求体缓存到网关中,以便在后续的请求中重复使用。这个过滤器通常用于优化跨集群的服务通信。

当使用微服务架构时,服务之间的通信可能需要经过网关进行路由和转发。在某些情况下,多个服务可能需要对同一个请求体进行处理,但由于HTTP请求的特性,请求体在传递过程中只能被读取一次。为了解决这个问题,AdaptCachedBodyGlobalFilter通过缓存请求体的方式,使得多个服务可以在后续的请求中重复使用该请求体。

通过缓存请求体,AdaptCachedBodyGlobalFilter可以提高服务之间的通信效率,减少不必要的数据传输和处理。它可以避免在每个服务中都重新读取请求体,从而节省了网络带宽和服务资源。

需要注意的是,AdaptCachedBodyGlobalFilter只能用于幂等的请求,因为对于非幂等的请求,重复使用缓存的请求体可能会导致数据不一致或产生意外的副作用。

AdaptCachedBodyGlobalFilter的作用是在网关层对请求体进行缓存,以提高跨集群服务通信的效率。

那么他是如何缓存的呢?
我总结成如下步骤:
AdaptCachedBodyGlobalFilter通过以下步骤来缓存请求体:

当请求到达网关时,AdaptCachedBodyGlobalFilter会拦截该请求。

首先,它会检查请求的方法(HTTP verb)是否是幂等的,例如GET、HEAD、OPTIONS等。如果请求方法不是幂等的,过滤器将不会缓存请求体,而是继续将请求传递给下一个处理程序。

如果请求方法是幂等的,AdaptCachedBodyGlobalFilter会读取请求的内容(请求体),并将其缓存到网关的内存中。通常,缓存会使用一种合适的数据结构(例如字典或哈希表)来存储请求体。

缓存的请求体将与请求的唯一标识(例如请求的URL或请求头中的某个字段)相关联,以便在后续的请求中可以根据标识进行查找和重用。

当后续的请求到达网关时,AdaptCachedBodyGlobalFilter会检查请求的唯一标识,并尝试从缓存中获取相应的请求体。

如果找到了缓存的请求体,过滤器会将其重新注入到当前请求中,以便后续的处理程序可以使用该请求体进行处理。

通过以上步骤,AdaptCachedBodyGlobalFilter实现了对请求体的缓存和重用,提高了跨集群服务通信的效率。这样,多个服务可以在后续的请求中共享和重复使用同一个请求体,避免了重复的数据传输和处理。
具体的实现方法可以查看对应源码
在这里插入图片描述

NettyWriteResponseFilter

NettyWriteResponseFilter是一个过滤器,通常用于在网关层对响应进行处理和修改。它的主要作用是在响应发送到客户端之前,对响应进行一些额外的操作。

具体来说,NettyWriteResponseFilter的功能包括:

修改响应头信息:可以通过该过滤器修改响应的头部信息,例如添加、删除或修改特定的响应头字段。

响应内容转换:可以对响应的内容进行转换,例如将响应体从一种格式转换为另一种格式,例如JSON到XML的转换。

响应内容加密或解密:如果需要对响应进行加密或解密,可以使用该过滤器来执行相应的操作。

响应内容压缩:可以使用该过滤器对响应的内容进行压缩,以减小传输的数据量,提高网络传输效率。

响应内容缓存:在某些场景下,可以使用该过滤器对响应进行缓存,以提高响应速度和减轻后端服务的压力。

NettyWriteResponseFilter通常作为网关中的一个全局过滤器或者特定路由的过滤器链中的一个过滤器来使用。它可以对响应进行灵活的处理和修改,以满足特定的需求和业务逻辑。

ForwardPathFilter

如下是我的请求走到这一个过滤器的时候的情况,可以发现在这里它已经决定好了我当前的这个路径是需要路由到的一个位置。
在这里插入图片描述

ForwardPathFilter 是 Spring Cloud Gateway 中的一个过滤器,其主要作用是在请求转发(Forward)时,处理请求路径的修改和重写。它通常用于将请求从一个路径转发到另一个路径,并且可以在此过程中对请求路径进行修改。

具体作用和用例包括:

路径重写:可以将请求的路径重写为另一个路径,用于实现请求路径的重定向或路由。

路径添加:可以在现有路径的基础上添加额外的路径段,实现更复杂的路由逻辑。

路径删除:可以删除请求路径中的某些部分,以实现路径的简化。

路径替换:可以使用正则表达式等方式,将请求路径中的某些部分替换为其他内容。

举个例子,假设我现在一个网关路由,将 /v1/product 的请求转发到后端服务的 /products 路径上。我就可以使用 ForwardPathFilter 来实现这个转发,并且将请求路径中的 /v1 部分重写为空,从而实现路径的修改。

这个过滤器在网关路由的配置中,可以通过配置 predicates 和 filters 来实现不同的路径转发和修改需求。
如果想要实现我上面说的重置路由规则,你就直接继承这个类并且重写方法,然后设定为Spring的一个bean即可。

import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.HttpHeaders;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
/**
* @author 张锦标
*/
@Component
public class CustomForwardPathFilter extends ForwardPathFilter {

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        // 在这里实现您的自定义逻辑
        // 可以修改请求的路径或执行其他操作
        // 调用父类的方法来执行默认的ForwardPathFilter行为
        return super.filter(exchange, chain);
    }
}

RouteToRequestUrlFilter

RouteToRequestUrlFilter是Spring Cloud Gateway的一个过滤器,其主要作用是根据目标服务的URI来构建新的请求URI。这个过滤器通常在路由过程中使用,用于将客户端请求的URI映射到目标服务的URI,从而实现请求的转发。

具体来说,RouteToRequestUrlFilter的主要工作包括:

解析路由定义中的目标URI:它会从路由配置中获取目标服务的URI,通常是通过uri属性指定的。

构建新的请求URI:使用目标服务的URI和原始请求的URI来构建新的请求URI。这个新的URI将被用于将请求转发到目标服务。

更新请求的URI属性:将构建好的新URI应用到请求对象中,以确保后续的处理步骤使用正确的URI来路由请求。

示例使用:

假设您有一个Spring Cloud Gateway路由定义如下:

routes:
  - id: my-route
    uri: http://example.com
    predicates:
      - Path=/my-service/**

当客户端发送一个请求到网关,如http://gateway-server/my-service/resource,RouteToRequestUrlFilter将会解析路由配置中的uri属性(http://example.com),然后构建新的请求URI为http://example.com/resource。接下来,这个新的URI将被用于将请求转发到http://example.com上的/resource路径。

RouteToRequestUrlFilter是一个关键的过滤器,用于将客户端请求映射到目标服务的URI,从而实现路由和请求转发。

最后一步实现的请求路径的修改,就是在这个类中执行的,可以看到这里的两行代码

URI mergedUrl = UriComponentsBuilder.fromUri(uri).scheme(routeUri.getScheme()).host(routeUri.getHost()).port(routeUri.getPort()).build(encoded).toUri();
//这一行代码可以修改request请求要请求的路径
exchange.getAttributes().put(ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR, mergedUrl);

在这里插入图片描述
我之前试图在我自己的全局过滤器设定新的请求路径,结果每次都没生效,现在我终于知道原因了哈哈哈哈。所以说看源码还是有用。

WebSocketRoutingFilter

WebSocketRoutingFilter 是 Spring Cloud Gateway 中的一个过滤器,它用于处理 WebSocket 协议的请求,将 WebSocket 请求路由到目标 WebSocket 服务器。

具体来说,WebSocketRoutingFilter 的主要功能包括:

检测请求是否为 WebSocket 请求:它会检查客户端发来的请求是否包含 WebSocket 协议相关的标识,如 Upgrade 头部中是否包含 “websocket”。

构建 WebSocket 目标服务的 URI:如果请求被识别为 WebSocket 请求,过滤器将会根据路由配置中的目标 URI(通常是 WebSocket 服务器的地址)构建 WebSocket 目标服务的 URI。

路由 WebSocket 请求:过滤器将 WebSocket 请求路由到目标 WebSocket 服务器,以建立 WebSocket 连接。

连接转发:一旦 WebSocket 连接建立成功,过滤器会将客户端和目标 WebSocket 服务器之间的数据流量进行转发,使客户端能够与 WebSocket 服务器进行双向通信。

示例使用:

假设有一个 Spring Cloud Gateway 路由定义,用于将 WebSocket 请求转发到目标 WebSocket 服务器:

routes:
  - id: websocket-route
    uri: ws://websocket-server
    predicates:
      - Path=/ws/**

NettyRoutingFilter

NettyRoutingFilter 是 Spring Cloud Gateway 中的一个过滤器,它负责将请求路由到目标服务并处理与目标服务之间的通信。这个过滤器是基于 Netty 框架实现的,用于处理非阻塞的异步请求和响应。

具体来说,NettyRoutingFilter 的主要作用包括:

负责将请求路由到目标服务:根据路由规则和请求的 URI,它决定了请求应该被路由到哪个目标服务。这通常涉及到根据请求的路径、主机名等信息来匹配路由规则,然后将请求发送给目标服务。

处理异步和非阻塞的请求:Spring Cloud Gateway 基于 Netty 提供了非阻塞的异步请求处理能力,允许处理大量并发请求而不会阻塞线程。NettyRoutingFilter 利用 Netty 的异步处理机制来实现这一点,从而提高了网关的性能和吞吐量。

处理请求和响应的转发:一旦确定了目标服务,过滤器会负责将请求和响应转发到目标服务,同时进行请求和响应的转换。这包括将请求头、请求体、响应头、响应体等内容从网关传递给目标服务,并从目标服务接收响应并返回给客户端。

处理请求失败和错误情况:如果请求无法成功路由到目标服务或者目标服务返回错误响应,NettyRoutingFilter 可以负责处理这些情况,并根据配置的策略来处理请求失败或错误的情况。

总之,NettyRoutingFilter 是 Spring Cloud Gateway 中关键的过滤器之一,它实现了请求的路由和异步非阻塞的请求处理,允许网关处理大量并发请求并将它们路由到目标服务。这有助于提高网关的性能和可扩展性。
在这一个过滤器中,会对你的请求头等信息进行一些操作
在这里插入图片描述

ForwardRoutingFilter

来到最后一个过滤器,最最最关键的一个过滤器,也就是我们请求转发过滤器。
ForwardRoutingFilter 是 Spring Cloud Gateway 中的一个过滤器(filter),用于实现请求的转发。Spring Cloud Gateway 是一个基于 Spring Framework 和 Spring Boot 的微服务网关,它提供了一种灵活而强大的方式来管理和路由微服务应用程序的请求流量。

ForwardRoutingFilter 的主要作用是将请求转发到指定的目标地址,通常是另一个微服务或后端服务。这个过滤器通常用于实现反向代理和请求的转发,将来自客户端的请求重新定向到后端服务,然后将后端服务的响应返回给客户端。

在 Spring Cloud Gateway 中,你可以通过配置路由规则来定义哪些请求应该由 ForwardRoutingFilter 这个过滤器处理,并指定转发的目标地址。

spring:
  cloud:
    gateway:
      routes:
        - id: forward_route
          uri: http://backend-service:8080  # 后端服务的地址
          predicates:
            - Path=/api/**  # 匹配以 /api/ 开头的请求
          filters:
            - ForwardRoutingFilter   # 使用 ForwardRoutingFilter 进行请求转发

在这个示例中,路由规则指定了将以 “/api/” 开头的请求转发到后端服务的地址 http://backend-service:8080。ForwardRoutingFilter 将负责将这些请求转发到指定的地址,并将响应返回给客户端。

总之,ForwardRoutingFilter 是 Spring Cloud Gateway 中用于请求转发的关键过滤器,它允许你配置路由规则来定制请求的转发行为,从而实现反向代理和路由功能。

DispatcherHandler 是什么?

DispatcherHandler 是 Spring Framework 中用于处理 Web 请求的核心组件之一。它的主要作用是根据请求的 URL 路径将请求分发给不同的处理器(Handler),并协调执行请求处理的过程。DispatcherHandler 的具体职责包括以下几个方面:

URL 路径匹配:DispatcherHandler 根据请求的 URL 路径来确定应该由哪个处理器来处理请求。它会根据配置的请求映射规则(如@Controller 注解、@RequestMapping 注解等)将请求路由到相应的 Controller 方法。

处理器适配:一旦确定了请求应该由哪个 Controller 来处理,DispatcherHandler 会负责创建一个适配器(HandlerAdapter)来执行具体的 Controller 方法。不同类型的 Controller 可能有不同的适配器,例如处理常规请求的 Controller 适配器、处理异步请求的适配器等。

请求处理:DispatcherHandler 将请求和适配器传递给适配器,然后适配器负责调用相应的 Controller 方法来处理请求。Controller 方法执行后会生成一个模型(Model)对象,用于渲染视图。

视图解析:一旦请求处理完成,DispatcherHandler 还负责将模型传递给视图解析器(ViewResolver)来解析视图的名称,并生成实际的视图对象。这个视图对象通常是一个 HTML 模板、JSON 数据、XML 数据等,具体取决于请求和配置。

视图渲染:最后,DispatcherHandler 将生成的视图渲染到响应中,生成最终的响应内容,并将其返回给客户端浏览器或调用者。

⭐如何确定最后的路由路径?

我们知道,我们可以再Gateway网关中自定义过滤器,并且实现Ordered接口来对过滤器的执行顺序进行排序。如下图我实现了三个自定义的全局过滤器。
在这里插入图片描述

并且,当你实现全局过滤器接口的时候,你必须实现如下方法
public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain)
其中exchange参数非常重要,他就是你的请求以及对你请求的响应。而chain就是上面的过滤器链条。
在这里插入图片描述

而我们的过滤器链的作用,其实就是对request和response这两个重要的类进行操作。
比如我可以使用exchange.mutate方法来对request和response进行修改。

exchange = exchange.mutate().request(build -> {
            try {
                build.uri(
                        new URI("http://localhost:8080/v1/product?productId=1"))
                        .build();
            } catch (URISyntaxException e) {
                throw new RuntimeException(e);
            }
        }
).build();

如下是我修改request之前的请求体内容。
在这里插入图片描述

如下就是我修改URI之后的request请求体的内容。
在这里插入图片描述

在这里我们把这个reqeust给他修改有着重大意义,这意味着只要对加密后的数据进行解密后,去修改这个request中的内容,我们就能再一次成功的将我们的请求路由到我们指定的路径。
在这里插入图片描述

而之后,我们最终路由到的请求路径位置,保存在了DefaultServerWebExchange的attributes中。
在这里插入图片描述

最后只要进入到ForwardRoutingFilter
在这里插入图片描述

在这里请求完成了最终的处理,然后进行转发,发送到对应的处理类去处理。
这时候我们看提供远程服务调用的类的调用栈即可。
在这里插入图片描述

下文:如何根据过滤器链设计一个自己的数字签名?如何对URL上的参数进行加密解密来保证数据安全性?

敬请期待

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

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

相关文章

一文拿捏Spring之AOP

Spring 1.Spring的理解 1.狭义上 指SpringFramework&#xff0c;特别的控制反转、依赖注入、面向切面、等特性 2.广义上 Spring家族的一系列产品&#xff0c;像SpringMVC、SpringBoot、SpringCloud等 2.aop &#x1f31f;面试题(aop): 简单介绍一下AOP&#xff1f; aop…

【userfaultfd】2021强网杯notebook

程序分析 老规矩&#xff0c;看下启动脚本 开启了 smep、smap、kaslr 保护&#xff0c;当然 kvm64 默认开启 kpti 保护 文件系统初始化脚本 #!/bin/sh /bin/mount -t devtmpfs devtmpfs /dev chown root:tty /dev/console chown root:tty /dev/ptmx chown root:tty /dev/tty…

SAAJ:SOAP with Attachments API for Java

介绍 支持带附件的SOAP消息Java接口&#xff08;SAAJ&#xff1a;SOAP with Attachments API for Java&#xff09;&#xff0c;定义了一套API&#xff0c;使开发者可以产生、消费遵从SOAP 1.1, SOAP 1.2, 和SOAP Attachments Feature的消息。 2019年SAAJ更改为新的名字&…

MIP精确算法的关键——确定界

目录 1.界是什么&#xff1f; 2. 如何更新上下界 2.1 以分支定界为框架的一系列算法 2.2 benders分解 MIP精确算法包含&#xff0c;分支定界、分支切割、分支定价还有benders分解等等。前者是以分支定界为框架的一类算法&#xff1b;后者是以分解为框架的一类算法。甚至还包…

Springboot学习笔记——1

Springboot学习笔记——1 一、快速上手Springboot1.1、Springboot入门程序开发1.1.1、IDEA创建Springboot项目1.1.2、官网创建Springboot项目1.1.3、阿里云创建Springboot项目1.1.4、手工制作Springboot项目 1.2、隐藏文件或文件夹1.3、入门案例解析1.3.1、parent1.3.2、starte…

嵌入式软件架构基础设施设计方法

大家好&#xff0c;今天分享一篇嵌入式软件架构设计相关的文章。 软件架构这东西&#xff0c;众说纷纭&#xff0c;各有观点。在我看来&#xff0c;软件架构是软件系统的基本结构&#xff0c;包含其组件、组件之间的关系、组件设计与演进的规则&#xff0c;以及体现这些规则的基…

Nginx高级 第一部分:扩容

Nginx高级 第一部分&#xff1a;扩容 通过扩容提升整体吞吐量 1.单机垂直扩容&#xff1a;硬件资源增加 云服务资源增加 整机&#xff1a;IBM、浪潮、DELL、HP等 CPU/主板&#xff1a;更新到主流 网卡&#xff1a;10G/40G网卡 磁盘&#xff1a;SAS(SCSI) HDD&#xff08;机械…

【C/C++笔试练习】——常量指针和指针常量、结构体内存分配、统计输入的字母个数、排序子序列、倒置字符串

文章目录 C/C笔试练习1.常量指针和指针常量&#xff08;1&#xff09;常量指针和指针常量的定义&#xff08;2&#xff09;判别常量指针和指针常量&#xff08;3&#xff09;常量指针和指针常量的特性 2.结构体内存分配&#xff08;4&#xff09;计算结构体大小&#xff08;5&a…

【计算机】CPU,芯片以及操作系统概述

1.CPU 什么是CPU? CPU&#xff08;Central Processing Unit&#xff09;是计算机系统的运算和控制核心&#xff0c;是信息处理、程序运行的最终执行单元&#xff0c;相当于系统的“大脑”。 CPU的工作流程&#xff1f; CPU 的工作流程分为以下 5 个阶段&#xff1a;取指令…

C++ -- 学习系列 关联式容器 set 与 map

一 关联式容器是什么&#xff1f; c 中有两种容器类型&#xff1a;关联式容器与序列式容器&#xff08;顺序容器&#xff09; 关联式中的容器是按照关键字来存储与访问的&#xff0c;序列式容器&#xff08;顺序容器&#xff09;则是元素在容器中的相对位置来存储与访问的。…

C++标准模板(STL)- 类型支持 ()

对象、引用、函数&#xff08;包括函数模板特化&#xff09;和表达式具有称为类型的性质&#xff0c;它限制了对这些实体所容许的操作&#xff0c;并给原本寻常的位序列提供了语义含义。 附加性基本类型及宏 实现定义的空指针常量 NULL 定义于头文件 <clocale> 定义于…

2.类与对象 拜访对象村

2.1 椅子大战 在图形接口画出正方形、圆形与三角形。当用户选点图形时&#xff0c;图形需要顺时针转360并依据形状的不同播放播放不同的AIF文件。胜者可以坐上名贵宝椅。 面向过程&#xff1a; rotate(shapeNum) {//旋转360 } playSound(shapeNum) {//查询播放哪个AIF文件//播…

嵌入式Linux应用开发-驱动大全-同步与互斥②

嵌入式Linux应用开发-驱动大全-同步与互斥② 第一章 同步与互斥②1.3 原子操作的实现原理与使用1.3.1 原子变量的内核操作函数1.3.2 原子变量的内核实现1.3.2.1 ATOMIC_OP在 UP系统中的实现1.3.2.2 ATOMIC_OP在 SMP系统中的实现 1.3.3 原子变量使用案例1.3.4 原子位介绍1.3.4.1…

pyqt5使用经验总结

pyqt5环境配置注意&#xff1a; 安装pyqt5 pip install PyQt5 pyqt5-tools 环境变量-创建变量名&#xff1a; 健名&#xff1a;QT_QPA_PLATFORM_PLUGIN_PATH 值为&#xff1a;Lib\site-packages\PyQt5\Qt\plugins pyqt5经验2&#xff1a; 使用designer.exe进行设计&#xff1…

Maven - MacOS 快速安装

配置信息 Maven 版本&#xff1a;3.6.3Maven 地址&#xff1a;Index of /dist/maven/maven-3IDEA&#xff1a;2023 Tips&#xff1a;Maven 版本最好不要超过 3.8.0&#xff0c;最新版 Maven 会不兼容一些配置信息。上面的 Maven 地址里可以选择自己想下载的版本&#xff08;这…

【源码】hamcrest 源码阅读及空对象模式、模板方法模式的应用

文章目录 前言1. 类图概览2. 源码阅读2.1 抽象类 BaseMatcher2.1 接口 Description提炼模式&#xff1a;空对象模式 2. 接口 Description 与 SelfDescribing 配合使用提炼模式 模板方法 后记 前言 hamcrest &#xff0c;一个被多个测试框架依赖的包。听说 hamcrest 的源码质量…

【maven】idea中基于maven-webapp骨架创建的web.xml问题

IDEA中基于maven-webapp骨架创建的web工程&#xff0c;默认的web.xml是这样的。 <!DOCTYPE web-app PUBLIC"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN""http://java.sun.com/dtd/web-app_2_3.dtd" ><web-app><display-name…

go语法入门2

字符串 使用双引号或反引号引起来的任意个字符。它是字面常量。 func main() {var a "abc\n测试" // \n换行fmt.Println(a) } abc 测试func main() {var a "abc\n\t测试" \\换行后在tabfmt.Println(a) } abc测试func main() {var a abc测试 …

CppCheck静态代码检查工具教程【Windows和Linux端】

目录 1、背景 2、特性介绍 2.1、检查结果 2.2、检查范围 2.3、支持的检查规则&#xff08;列举一些&#xff09;: 2.4、自定义规则 3、linux 端 4、windows 端 1、背景 最近调研了几款 c/c 代码静态检查工具&#xff0c;包括 cppcheck、cpplint、cppdepend、splint、ts…