第一反應,參考zuul 的實現,自定義斷言,然后從上下中獲取版本信息即可。但由於 spring cloud gateway 是基於webflux 的反應式編程,所以傳統的TTL或者 RequestContextHolder 都不能正確的維護上下文請求。
先來看 spring clou的 gateway 默認的lb 策略實現 LoadBalancerClientFilter
public class LoadBalancerClientFilter implements GlobalFilter, Ordered { @Override public int getOrder() { return LOAD_BALANCER_CLIENT_FILTER_ORDER; } @Override @SuppressWarnings("Duplicates") public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { return chain.filter(exchange); } protected ServiceInstance choose(ServerWebExchange exchange) { return loadBalancer.choose( ((URI) exchange.getAttribute(GATEWAY_REQUEST_URL_ATTR)).getHost()); } }
我們只需要重寫 choose 方法,把上下文請求傳遞到路由斷言中即可,如下
@Override protected ServiceInstance choose(ServerWebExchange exchange) { HttpHeaders headers = exchange.getRequest().getHeaders(); return loadBalancer.choose(((URI) exchange.getAttribute(GATEWAY_REQUEST_URL_ATTR)).getHost(), headers); }
然后在路由斷言中通過 PredicateKey獲取到即可
public abstract class AbstractDiscoveryEnabledPredicate extends AbstractServerPredicate { /** * {@inheritDoc} */ @Override public boolean apply(@Nullable PredicateKey input) { return input != null && input.getServer() instanceof NacosServer && apply((NacosServer) input.getServer(), (HttpHeaders) input.getLoadBalancerKey()); } }
最后根據版本來計算
public class GrayMetadataAwarePredicate extends AbstractDiscoveryEnabledPredicate { @Override protected boolean apply(NacosServer server, HttpHeaders headers) { PigxRibbonRuleProperties ribbonProperties = SpringContextHolder.getBean(PigxRibbonRuleProperties.class); if (!ribbonProperties.isGrayEnabled()) { log.debug("gray closed,GrayMetadataAwarePredicate return true"); return true; } final Map<String, String> metadata = server.getMetadata(); String version = metadata.get(CommonConstants.VERSION); // 判斷Nacos服務是否有版本標簽 if (StrUtil.isBlank(version)) { log.debug("nacos server tag is blank ,GrayMetadataAwarePredicate return true"); return true; } // 判斷請求中是否有版本 String target = headers.getFirst(CommonConstants.VERSION); if (StrUtil.isBlank(target)) { log.debug("request headers version is blank,GrayMetadataAwarePredicate return true"); return true; } log.debug("請求版本:{} ,當前服務版本:{}", target, version); return target.equals(version); } }
參考:https://segmentfault.com/a/1190000019709733?utm_source=tag-newest