文章目录
- 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上的参数进行加密解密来保证数据安全性?
敬请期待