有没有一种方法可以在路由之前应用过滤器或代码(Spring Cloud Gateway)



我正在编写一个API网关,该网关必须基于MAC地址路由请求。终点示例:

/api/v2/device/AABBCCDDEEFF
/api/v2/device/AABBCCDDEEFF/metadata
/api/v2/device/search?deviceId=AABBCCDDEEFF

我已经编写了一个自定义谓词工厂,它提取MAC地址,执行必要的逻辑来确定MAC地址应该路由到哪个URL,然后将该信息存储在ServerWebExchange属性上。

public class CustomRoutePredicateFactory extends AbstractRoutePredicateFactory<CustomRoutePredicateFactory.Config> {
// Fields/Constructors Omitted
private static final String IP_ATTRIBUTE = "assignedIp";
private static final String MAC_ATTRIBUTE = "mac";
@Override
public Predicate<ServerWebExchange> apply(Config config) {
return (ServerWebExchange exchange) -> {
String mac = exchange.getAttributes().get(MAC_ATTRIBUTE);
if(mac == null){
mac = extractMacAddress(exchange);
}
if(!exchange.getAttributes().contains(IP_ATTRIBUTE)){
exchange.getAttributes().put(IP_ATTRIBUTE, findAssignedIp(mac);
}
return config.getRouteIp().equals(exchange.getAttribute(IP_ATTRIBUTE));
});
}
// Config Class & utility methods omitted
}

注意:为了简洁起见,此实现大大简化了

通过这种实现,我能够保证MAC只提取一次,并且确定请求属于哪个URL的逻辑只执行一次。对谓词工厂的第一次调用将提取并设置ServerWebExchange属性上的信息,对谓词工厂进行的任何进一步调用都将检测这些属性,并使用它们来确定它们是否匹配。

这很管用,但不是特别整洁。如果我可以在应用程序尝试匹配路由之前,以某种方式为进入网关的每个请求设置Exchange属性,这将更容易、更简单。然后,过滤器可以是一个简单的谓词,用于检查Exchange属性是否相等。

我已经把文档读了好几遍,但似乎什么都不可能。过滤器的作用域总是特定的路由,并且只有在路由匹配后才运行。可能会使第一个路由成为另一个执行必要代码、设置预期属性并始终返回false的谓词,但我能保证该谓词始终运行第一个吗?似乎应该支持这种用例,但我一辈子都找不到一种看起来不像黑客的方法。有什么想法吗?

使用WebFilter而不是GatewayFilterGlobalFilter。它们仅在谓词链之后应用。而CCD_ 5是一个拦截器。

@Component
public class CustomRoutePredicateFactory implements WebFilter, Ordered {
private static final String IP_ATTRIBUTE = "assignedIp";
private static final String MAC_ATTRIBUTE = "mac";
@Override
public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
String mac = (String) exchange.getAttributes().computeIfAbsent(MAC_ATTRIBUTE, key -> extractMacAddress(exchange));
exchange.getAttributes().computeIfAbsent(IP_ATTRIBUTE, key -> findAssignedIp(mac));
return chain.filter(exchange);
}
@Override
public int getOrder() {
return Ordered.HIGHEST_PRECEDENCE;
}

}

我认为您的方法是有意义的,因为您希望它在过滤器之前运行。

您是否考虑过使用带有订单集的GlobalFilter?您可以确保它始终是第一个运行的筛选器。您还可以通过更改请求并在交换机上设置GATEWAY_REQUEST_URL_ATTR属性来修改ServerWebExchange中的URL。

看看PrefixPathGatewayFilterFactory,了解如何更改路由到的URI的示例。

您可以通过实现org.springframework.core.Ordered接口在全局过滤器上设置订单。

话虽如此,这仍然有点像黑客攻击,但这是一种替代方法。

我认为重写RoutePredicateHandlerMapping类可能会对您有所帮助。参见:org.springframework.web.reactive.handler.AbstractHandlerMapping#getHandler

相关内容

  • 没有找到相关文章

最新更新