diff --git a/CHANGELOG.md b/CHANGELOG.md
index 7b3f17d2d..0fd331294 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -3,4 +3,5 @@
- [Feature: Support parse ratelimit rule expression labels.](https://github.com/Tencent/spring-cloud-tencent/pull/183)
-- [fix:Router support request label.](https://github.com/Tencent/spring-cloud-tencent/pull/165)
\ No newline at end of file
+- [Feature: Router support request label.](https://github.com/Tencent/spring-cloud-tencent/pull/165)
+- [Feature: Support router expression label](https://github.com/Tencent/spring-cloud-tencent/pull/190)
diff --git a/spring-cloud-starter-tencent-polaris-router/pom.xml b/spring-cloud-starter-tencent-polaris-router/pom.xml
index 94a69d9bc..6f0fa315d 100644
--- a/spring-cloud-starter-tencent-polaris-router/pom.xml
+++ b/spring-cloud-starter-tencent-polaris-router/pom.xml
@@ -33,6 +33,13 @@
spring-cloud-starter-openfeign
true
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+ true
+
+
diff --git a/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/RouterRuleLabelResolver.java b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/RouterRuleLabelResolver.java
new file mode 100644
index 000000000..5ab6e549f
--- /dev/null
+++ b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/RouterRuleLabelResolver.java
@@ -0,0 +1,75 @@
+/*
+ * Tencent is pleased to support the open source community by making Spring Cloud Tencent available.
+ *
+ * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
+ *
+ * Licensed under the BSD 3-Clause License (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://opensource.org/licenses/BSD-3-Clause
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed
+ * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+ * CONDITIONS OF ANY KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ *
+ */
+
+package com.tencent.cloud.polaris.router;
+
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import com.tencent.cloud.common.util.ExpressionLabelUtils;
+import com.tencent.cloud.polaris.context.ServiceRuleManager;
+import com.tencent.polaris.client.pb.ModelProto;
+import com.tencent.polaris.client.pb.RoutingProto;
+
+import org.springframework.util.CollectionUtils;
+
+/**
+ * Resolve label expressions from routing rules.
+ * @author lepdou 2022-05-19
+ */
+public class RouterRuleLabelResolver {
+
+ private final ServiceRuleManager serviceRuleManager;
+
+ public RouterRuleLabelResolver(ServiceRuleManager serviceRuleManager) {
+ this.serviceRuleManager = serviceRuleManager;
+ }
+
+ public Set getExpressionLabelKeys(String namespace, String sourceService, String dstService) {
+ List rules = serviceRuleManager.getServiceRouterRule(namespace, sourceService, dstService);
+
+ if (CollectionUtils.isEmpty(rules)) {
+ return Collections.emptySet();
+ }
+
+ Set expressionLabels = new HashSet<>();
+
+ for (RoutingProto.Route rule : rules) {
+ List sources = rule.getSourcesList();
+ if (CollectionUtils.isEmpty(sources)) {
+ continue;
+ }
+ for (RoutingProto.Source source : sources) {
+ Map labels = source.getMetadataMap();
+ if (CollectionUtils.isEmpty(labels)) {
+ continue;
+ }
+ for (String labelKey : labels.keySet()) {
+ if (ExpressionLabelUtils.isExpressionLabel(labelKey)) {
+ expressionLabels.add(labelKey);
+ }
+ }
+ }
+ }
+
+ return expressionLabels;
+ }
+}
diff --git a/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/config/RouterAutoConfiguration.java b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/config/RouterAutoConfiguration.java
index 950638406..5065b09b5 100644
--- a/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/config/RouterAutoConfiguration.java
+++ b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/config/RouterAutoConfiguration.java
@@ -19,6 +19,8 @@
package com.tencent.cloud.polaris.router.config;
import com.tencent.cloud.common.metadata.config.MetadataLocalProperties;
+import com.tencent.cloud.polaris.context.ServiceRuleManager;
+import com.tencent.cloud.polaris.router.RouterRuleLabelResolver;
import com.tencent.cloud.polaris.router.feign.PolarisCachingSpringLoadBalanceFactory;
import com.tencent.cloud.polaris.router.feign.RouterLabelInterceptor;
import com.tencent.cloud.polaris.router.resttemplate.PolarisLoadBalancerBeanPostProcessor;
@@ -44,8 +46,9 @@ public class RouterAutoConfiguration {
@Bean
public RouterLabelInterceptor routerLabelInterceptor(@Nullable RouterLabelResolver resolver,
- MetadataLocalProperties metadataLocalProperties) {
- return new RouterLabelInterceptor(resolver, metadataLocalProperties);
+ MetadataLocalProperties metadataLocalProperties,
+ RouterRuleLabelResolver routerRuleLabelResolver) {
+ return new RouterLabelInterceptor(resolver, metadataLocalProperties, routerRuleLabelResolver);
}
@Bean
@@ -58,4 +61,9 @@ public class RouterAutoConfiguration {
public PolarisLoadBalancerBeanPostProcessor polarisLoadBalancerBeanPostProcessor() {
return new PolarisLoadBalancerBeanPostProcessor();
}
+
+ @Bean
+ public RouterRuleLabelResolver routerRuleLabelResolver(ServiceRuleManager serviceRuleManager) {
+ return new RouterRuleLabelResolver(serviceRuleManager);
+ }
}
diff --git a/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/feign/FeignExpressionLabelUtils.java b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/feign/FeignExpressionLabelUtils.java
new file mode 100644
index 000000000..cf4408d37
--- /dev/null
+++ b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/feign/FeignExpressionLabelUtils.java
@@ -0,0 +1,81 @@
+/*
+ * Tencent is pleased to support the open source community by making Spring Cloud Tencent available.
+ *
+ * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
+ *
+ * Licensed under the BSD 3-Clause License (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://opensource.org/licenses/BSD-3-Clause
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed
+ * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+ * CONDITIONS OF ANY KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ *
+ */
+
+package com.tencent.cloud.polaris.router.feign;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+import com.tencent.cloud.common.util.ExpressionLabelUtils;
+import feign.RequestTemplate;
+import org.apache.commons.lang.StringUtils;
+
+import org.springframework.util.CollectionUtils;
+
+/**
+ * Resolve rule expression label from feign request.
+ * @author lepdou 2022-05-20
+ */
+public class FeignExpressionLabelUtils {
+
+ public static Map resolve(RequestTemplate request, Set labelKeys) {
+ if (CollectionUtils.isEmpty(labelKeys)) {
+ return Collections.emptyMap();
+ }
+
+ Map labels = new HashMap<>();
+
+ for (String labelKey : labelKeys) {
+ if (StringUtils.startsWithIgnoreCase(labelKey, ExpressionLabelUtils.LABEL_HEADER_PREFIX)) {
+ String headerKey = ExpressionLabelUtils.parseHeaderKey(labelKey);
+ if (StringUtils.isBlank(headerKey)) {
+ continue;
+ }
+ labels.put(labelKey, getHeaderValue(request, headerKey));
+ }
+ else if (StringUtils.startsWithIgnoreCase(labelKey, ExpressionLabelUtils.LABEL_QUERY_PREFIX)) {
+ String queryKey = ExpressionLabelUtils.parseQueryKey(labelKey);
+ if (StringUtils.isBlank(queryKey)) {
+ continue;
+ }
+ labels.put(labelKey, getQueryValue(request, queryKey));
+ }
+ else if (StringUtils.equalsIgnoreCase(ExpressionLabelUtils.LABEL_METHOD, labelKey)) {
+ labels.put(labelKey, request.method());
+ }
+ else if (StringUtils.equalsIgnoreCase(ExpressionLabelUtils.LABEL_URI, labelKey)) {
+ labels.put(labelKey, request.request().url());
+ }
+ }
+
+ return labels;
+ }
+
+ public static String getHeaderValue(RequestTemplate request, String key) {
+ Map> headers = request.headers();
+ return ExpressionLabelUtils.getFirstValue(headers, key);
+
+ }
+
+ public static String getQueryValue(RequestTemplate request, String key) {
+ return ExpressionLabelUtils.getFirstValue(request.queries(), key);
+ }
+}
diff --git a/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/feign/PolarisFeignLoadBalancer.java b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/feign/PolarisFeignLoadBalancer.java
index d9ac98b04..067332dd6 100644
--- a/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/feign/PolarisFeignLoadBalancer.java
+++ b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/feign/PolarisFeignLoadBalancer.java
@@ -19,11 +19,13 @@
package com.tencent.cloud.polaris.router.feign;
import java.util.Collection;
+import java.util.HashMap;
import java.util.Map;
import com.netflix.client.config.IClientConfig;
import com.netflix.loadbalancer.ILoadBalancer;
import com.netflix.loadbalancer.reactive.LoadBalancerCommand;
+import com.tencent.cloud.common.util.ExpressionLabelUtils;
import com.tencent.cloud.common.util.JacksonUtils;
import com.tencent.cloud.polaris.router.PolarisRouterContext;
import com.tencent.cloud.polaris.router.RouterConstants;
@@ -59,7 +61,13 @@ public class PolarisFeignLoadBalancer extends FeignLoadBalancer {
labelHeaderValues.forEach(labelHeaderValue -> {
Map labels = JacksonUtils.deserialize2Map(labelHeaderValue);
if (!CollectionUtils.isEmpty(labels)) {
- routerContext.setLabels(labels);
+ Map unescapeLabels = new HashMap<>(labels.size());
+ for (Map.Entry entry : labels.entrySet()) {
+ String escapedKey = ExpressionLabelUtils.unescape(entry.getKey());
+ String escapedValue = ExpressionLabelUtils.unescape(entry.getValue());
+ unescapeLabels.put(escapedKey, escapedValue);
+ }
+ routerContext.setLabels(unescapeLabels);
}
});
diff --git a/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/feign/RouterLabelInterceptor.java b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/feign/RouterLabelInterceptor.java
index 47d4cc1fe..48c3fb667 100644
--- a/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/feign/RouterLabelInterceptor.java
+++ b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/feign/RouterLabelInterceptor.java
@@ -18,14 +18,18 @@
package com.tencent.cloud.polaris.router.feign;
+import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
+import java.util.Set;
import com.tencent.cloud.common.metadata.MetadataContext;
import com.tencent.cloud.common.metadata.MetadataContextHolder;
import com.tencent.cloud.common.metadata.config.MetadataLocalProperties;
+import com.tencent.cloud.common.util.ExpressionLabelUtils;
import com.tencent.cloud.common.util.JacksonUtils;
import com.tencent.cloud.polaris.router.RouterConstants;
+import com.tencent.cloud.polaris.router.RouterRuleLabelResolver;
import com.tencent.cloud.polaris.router.spi.RouterLabelResolver;
import feign.RequestInterceptor;
import feign.RequestTemplate;
@@ -45,11 +49,14 @@ public class RouterLabelInterceptor implements RequestInterceptor, Ordered {
private final RouterLabelResolver resolver;
private final MetadataLocalProperties metadataLocalProperties;
+ private final RouterRuleLabelResolver routerRuleLabelResolver;
public RouterLabelInterceptor(RouterLabelResolver resolver,
- MetadataLocalProperties metadataLocalProperties) {
+ MetadataLocalProperties metadataLocalProperties,
+ RouterRuleLabelResolver routerRuleLabelResolver) {
this.resolver = resolver;
this.metadataLocalProperties = metadataLocalProperties;
+ this.routerRuleLabelResolver = routerRuleLabelResolver;
}
@Override
@@ -79,10 +86,38 @@ public class RouterLabelInterceptor implements RequestInterceptor, Ordered {
}
}
+ // labels from rule expression
+ String peerServiceName = requestTemplate.feignTarget().name();
+ Map ruleExpressionLabels = getRuleExpressionLabels(requestTemplate, peerServiceName);
+ labels.putAll(ruleExpressionLabels);
+
+
//local service labels
labels.putAll(metadataLocalProperties.getContent());
+ // Because when the label is placed in RequestTemplate.header,
+ // RequestTemplate will parse the header according to the regular, which conflicts with the expression.
+ // Avoid conflicts by escaping.
+ Map escapeLabels = new HashMap<>(labels.size());
+ for (Map.Entry entry : labels.entrySet()) {
+ String escapedKey = ExpressionLabelUtils.escape(entry.getKey());
+ String escapedValue = ExpressionLabelUtils.escape(entry.getValue());
+ escapeLabels.put(escapedKey, escapedValue);
+ }
+
// pass label by header
- requestTemplate.header(RouterConstants.ROUTER_LABEL_HEADER, JacksonUtils.serialize2Json(labels));
+ requestTemplate.header(RouterConstants.ROUTER_LABEL_HEADER, JacksonUtils.serialize2Json(escapeLabels));
+ }
+
+ private Map getRuleExpressionLabels(RequestTemplate requestTemplate, String peerService) {
+ Set labelKeys = routerRuleLabelResolver.getExpressionLabelKeys(MetadataContext.LOCAL_NAMESPACE,
+ MetadataContext.LOCAL_SERVICE, peerService);
+
+ if (CollectionUtils.isEmpty(labelKeys)) {
+ return Collections.emptyMap();
+ }
+
+ return FeignExpressionLabelUtils.resolve(requestTemplate, labelKeys);
}
+
}
diff --git a/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/resttemplate/PolarisLoadBalancerBeanPostProcessor.java b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/resttemplate/PolarisLoadBalancerBeanPostProcessor.java
index bdee51767..6fe192003 100644
--- a/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/resttemplate/PolarisLoadBalancerBeanPostProcessor.java
+++ b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/resttemplate/PolarisLoadBalancerBeanPostProcessor.java
@@ -19,6 +19,7 @@
package com.tencent.cloud.polaris.router.resttemplate;
import com.tencent.cloud.common.metadata.config.MetadataLocalProperties;
+import com.tencent.cloud.polaris.router.RouterRuleLabelResolver;
import com.tencent.cloud.polaris.router.spi.RouterLabelResolver;
import org.springframework.beans.BeansException;
@@ -51,9 +52,10 @@ public class PolarisLoadBalancerBeanPostProcessor implements BeanPostProcessor,
LoadBalancerClient loadBalancerClient = this.factory.getBean(LoadBalancerClient.class);
RouterLabelResolver routerLabelResolver = this.factory.getBean(RouterLabelResolver.class);
MetadataLocalProperties metadataLocalProperties = this.factory.getBean(MetadataLocalProperties.class);
+ RouterRuleLabelResolver routerRuleLabelResolver = this.factory.getBean(RouterRuleLabelResolver.class);
return new PolarisLoadBalancerInterceptor(loadBalancerClient, requestFactory,
- routerLabelResolver, metadataLocalProperties);
+ routerLabelResolver, metadataLocalProperties, routerRuleLabelResolver);
}
return bean;
}
diff --git a/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/resttemplate/PolarisLoadBalancerInterceptor.java b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/resttemplate/PolarisLoadBalancerInterceptor.java
index 53c2a3401..2e3e691f4 100644
--- a/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/resttemplate/PolarisLoadBalancerInterceptor.java
+++ b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/resttemplate/PolarisLoadBalancerInterceptor.java
@@ -20,13 +20,17 @@ package com.tencent.cloud.polaris.router.resttemplate;
import java.io.IOException;
import java.net.URI;
+import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
+import java.util.Set;
import com.tencent.cloud.common.metadata.MetadataContext;
import com.tencent.cloud.common.metadata.MetadataContextHolder;
import com.tencent.cloud.common.metadata.config.MetadataLocalProperties;
+import com.tencent.cloud.common.util.ExpressionLabelUtils;
import com.tencent.cloud.polaris.router.PolarisRouterContext;
+import com.tencent.cloud.polaris.router.RouterRuleLabelResolver;
import com.tencent.cloud.polaris.router.spi.RouterLabelResolver;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -54,18 +58,21 @@ public class PolarisLoadBalancerInterceptor extends LoadBalancerInterceptor {
private final LoadBalancerRequestFactory requestFactory;
private final RouterLabelResolver resolver;
private final MetadataLocalProperties metadataLocalProperties;
+ private final RouterRuleLabelResolver routerRuleLabelResolver;
private final boolean isRibbonLoadBalanceClient;
public PolarisLoadBalancerInterceptor(LoadBalancerClient loadBalancer,
LoadBalancerRequestFactory requestFactory,
RouterLabelResolver resolver,
- MetadataLocalProperties metadataLocalProperties) {
+ MetadataLocalProperties metadataLocalProperties,
+ RouterRuleLabelResolver routerRuleLabelResolver) {
super(loadBalancer, requestFactory);
this.loadBalancer = loadBalancer;
this.requestFactory = requestFactory;
this.resolver = resolver;
this.metadataLocalProperties = metadataLocalProperties;
+ this.routerRuleLabelResolver = routerRuleLabelResolver;
this.isRibbonLoadBalanceClient = loadBalancer instanceof RibbonLoadBalancerClient;
}
@@ -73,22 +80,22 @@ public class PolarisLoadBalancerInterceptor extends LoadBalancerInterceptor {
@Override
public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException {
final URI originalUri = request.getURI();
- String serviceName = originalUri.getHost();
- Assert.state(serviceName != null,
+ String peerServiceName = originalUri.getHost();
+ Assert.state(peerServiceName != null,
"Request URI does not contain a valid hostname: " + originalUri);
if (isRibbonLoadBalanceClient) {
- PolarisRouterContext routerContext = genRouterContext(request, body);
+ PolarisRouterContext routerContext = genRouterContext(request, body, peerServiceName);
- return ((RibbonLoadBalancerClient) loadBalancer).execute(serviceName,
+ return ((RibbonLoadBalancerClient) loadBalancer).execute(peerServiceName,
this.requestFactory.createRequest(request, body, execution), routerContext);
}
- return this.loadBalancer.execute(serviceName,
+ return this.loadBalancer.execute(peerServiceName,
this.requestFactory.createRequest(request, body, execution));
}
- private PolarisRouterContext genRouterContext(HttpRequest request, byte[] body) {
+ private PolarisRouterContext genRouterContext(HttpRequest request, byte[] body, String peerServiceName) {
Map labels = new HashMap<>();
// labels from downstream
@@ -109,6 +116,11 @@ public class PolarisLoadBalancerInterceptor extends LoadBalancerInterceptor {
}
}
+ Map ruleExpressionLabels = getExpressionLabels(request, peerServiceName);
+ if (!CollectionUtils.isEmpty(ruleExpressionLabels)) {
+ labels.putAll(ruleExpressionLabels);
+ }
+
//local service labels
labels.putAll(metadataLocalProperties.getContent());
@@ -117,4 +129,15 @@ public class PolarisLoadBalancerInterceptor extends LoadBalancerInterceptor {
return routerContext;
}
+
+ private Map getExpressionLabels(HttpRequest request, String peerServiceName) {
+ Set labelKeys = routerRuleLabelResolver.getExpressionLabelKeys(MetadataContext.LOCAL_NAMESPACE,
+ MetadataContext.LOCAL_SERVICE, peerServiceName);
+
+ if (CollectionUtils.isEmpty(labelKeys)) {
+ return Collections.emptyMap();
+ }
+
+ return ExpressionLabelUtils.resolve(request, labelKeys);
+ }
}
diff --git a/spring-cloud-tencent-commons/pom.xml b/spring-cloud-tencent-commons/pom.xml
index b9b853c2e..eae677526 100644
--- a/spring-cloud-tencent-commons/pom.xml
+++ b/spring-cloud-tencent-commons/pom.xml
@@ -83,6 +83,18 @@
true
+
+ org.springframework.boot
+ spring-boot-starter-web
+ true
+
+
+
+ org.springframework.boot
+ spring-boot-starter-webflux
+ true
+
+
org.springframework.boot
spring-boot-starter-test
diff --git a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/ExpressionLabelUtils.java b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/ExpressionLabelUtils.java
index 7e93fdb6a..26557aa3d 100644
--- a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/ExpressionLabelUtils.java
+++ b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/ExpressionLabelUtils.java
@@ -18,6 +18,7 @@
package com.tencent.cloud.common.util;
+import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
@@ -29,6 +30,8 @@ import javax.servlet.http.HttpServletRequest;
import org.apache.commons.lang.StringUtils;
import org.springframework.http.HttpCookie;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.HttpRequest;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.util.CollectionUtils;
import org.springframework.util.MultiValueMap;
@@ -41,16 +44,50 @@ import org.springframework.web.server.ServerWebExchange;
*/
public class ExpressionLabelUtils {
- private static final String LABEL_HEADER_PREFIX = "${http.header.";
- private static final int LABEL_HEADER_PREFIX_LEN = LABEL_HEADER_PREFIX.length();
- private static final String LABEL_QUERY_PREFIX = "${http.query.";
- private static final int LABEL_QUERY_PREFIX_LEN = LABEL_QUERY_PREFIX.length();
- private static final String LABEL_COOKIE_PREFIX = "${http.cookie.";
- private static final int LABEL_COOKIE_PREFIX_LEN = LABEL_COOKIE_PREFIX.length();
- private static final String LABEL_METHOD = "${http.method}";
- private static final String LABEL_URI = "${http.uri}";
-
- private static final String LABEL_SUFFIX = "}";
+ /**
+ * the expression prefix of header label.
+ */
+ public static final String LABEL_HEADER_PREFIX = "${http.header.";
+ /**
+ * the length of expression header label prefix.
+ */
+ public static final int LABEL_HEADER_PREFIX_LEN = LABEL_HEADER_PREFIX.length();
+ /**
+ * the expression prefix of query.
+ */
+ public static final String LABEL_QUERY_PREFIX = "${http.query.";
+ /**
+ * the length of expression query label prefix.
+ */
+ public static final int LABEL_QUERY_PREFIX_LEN = LABEL_QUERY_PREFIX.length();
+ /**
+ * the expression prefix of cookie.
+ */
+ public static final String LABEL_COOKIE_PREFIX = "${http.cookie.";
+ /**
+ * the length of expression cookie label prefix.
+ */
+ public static final int LABEL_COOKIE_PREFIX_LEN = LABEL_COOKIE_PREFIX.length();
+ /**
+ * the expression of method.
+ */
+ public static final String LABEL_METHOD = "${http.method}";
+ /**
+ * the expression of uri.
+ */
+ public static final String LABEL_URI = "${http.uri}";
+ /**
+ * the prefix of expression.
+ */
+ public static final String LABEL_PREFIX = "${";
+ /**
+ * the suffix of expression.
+ */
+ public static final String LABEL_SUFFIX = "}";
+ /**
+ * the escape prefix of label.
+ */
+ public static final String LABEL_ESCAPE_PREFIX = "$$$$";
public static boolean isExpressionLabel(String labelKey) {
if (StringUtils.isEmpty(labelKey)) {
@@ -66,6 +103,14 @@ public class ExpressionLabelUtils {
&& StringUtils.endsWith(labelKey, LABEL_SUFFIX);
}
+ public static String escape(String str) {
+ return StringUtils.replace(str, LABEL_PREFIX, LABEL_ESCAPE_PREFIX);
+ }
+
+ public static String unescape(String str) {
+ return StringUtils.replace(str, LABEL_ESCAPE_PREFIX, LABEL_PREFIX);
+ }
+
public static Map resolve(HttpServletRequest request, Set labelKeys) {
if (CollectionUtils.isEmpty(labelKeys)) {
return Collections.emptyMap();
@@ -75,15 +120,24 @@ public class ExpressionLabelUtils {
for (String labelKey : labelKeys) {
if (StringUtils.startsWithIgnoreCase(labelKey, LABEL_HEADER_PREFIX)) {
- String headerKey = labelKey.substring(LABEL_HEADER_PREFIX_LEN, labelKey.length() - 1);
+ String headerKey = parseHeaderKey(labelKey);
+ if (StringUtils.isBlank(headerKey)) {
+ continue;
+ }
labels.put(labelKey, request.getHeader(headerKey));
}
else if (StringUtils.startsWithIgnoreCase(labelKey, LABEL_QUERY_PREFIX)) {
- String queryKey = labelKey.substring(LABEL_QUERY_PREFIX_LEN, labelKey.length() - 1);
+ String queryKey = parseQueryKey(labelKey);
+ if (StringUtils.isBlank(queryKey)) {
+ continue;
+ }
labels.put(labelKey, getQueryValue(request.getQueryString(), queryKey));
}
else if (StringUtils.startsWithIgnoreCase(labelKey, LABEL_COOKIE_PREFIX)) {
- String cookieKey = labelKey.substring(LABEL_COOKIE_PREFIX_LEN, labelKey.length() - 1);
+ String cookieKey = parseCookieKey(labelKey);
+ if (StringUtils.isBlank(cookieKey)) {
+ continue;
+ }
labels.put(labelKey, getCookieValue(request.getCookies(), cookieKey));
}
else if (StringUtils.equalsIgnoreCase(LABEL_METHOD, labelKey)) {
@@ -106,15 +160,24 @@ public class ExpressionLabelUtils {
for (String labelKey : labelKeys) {
if (StringUtils.startsWithIgnoreCase(labelKey, LABEL_HEADER_PREFIX)) {
- String headerKey = labelKey.substring(LABEL_HEADER_PREFIX_LEN, labelKey.length() - 1);
+ String headerKey = parseHeaderKey(labelKey);
+ if (StringUtils.isBlank(headerKey)) {
+ continue;
+ }
labels.put(labelKey, getHeaderValue(exchange.getRequest(), headerKey));
}
else if (StringUtils.startsWithIgnoreCase(labelKey, LABEL_QUERY_PREFIX)) {
- String queryKey = labelKey.substring(LABEL_QUERY_PREFIX_LEN, labelKey.length() - 1);
+ String queryKey = parseQueryKey(labelKey);
+ if (StringUtils.isBlank(queryKey)) {
+ continue;
+ }
labels.put(labelKey, getQueryValue(exchange.getRequest(), queryKey));
}
else if (StringUtils.startsWithIgnoreCase(labelKey, LABEL_COOKIE_PREFIX)) {
- String cookieKey = labelKey.substring(LABEL_COOKIE_PREFIX_LEN, labelKey.length() - 1);
+ String cookieKey = parseCookieKey(labelKey);
+ if (StringUtils.isBlank(cookieKey)) {
+ continue;
+ }
labels.put(labelKey, getCookieValue(exchange.getRequest(), cookieKey));
}
else if (StringUtils.equalsIgnoreCase(LABEL_METHOD, labelKey)) {
@@ -128,7 +191,52 @@ public class ExpressionLabelUtils {
return labels;
}
- private static String getQueryValue(String queryString, String queryKey) {
+ public static Map resolve(HttpRequest request, Set labelKeys) {
+ if (CollectionUtils.isEmpty(labelKeys)) {
+ return Collections.emptyMap();
+ }
+
+ Map labels = new HashMap<>();
+
+ for (String labelKey : labelKeys) {
+ if (StringUtils.startsWithIgnoreCase(labelKey, LABEL_HEADER_PREFIX)) {
+ String headerKey = parseHeaderKey(labelKey);
+ if (StringUtils.isBlank(headerKey)) {
+ continue;
+ }
+ labels.put(labelKey, getHeaderValue(request, headerKey));
+ }
+ else if (StringUtils.startsWithIgnoreCase(labelKey, LABEL_QUERY_PREFIX)) {
+ String queryKey = parseQueryKey(labelKey);
+ if (StringUtils.isBlank(queryKey)) {
+ continue;
+ }
+ labels.put(labelKey, getQueryValue(request, queryKey));
+ }
+ else if (StringUtils.equalsIgnoreCase(LABEL_METHOD, labelKey)) {
+ labels.put(labelKey, request.getMethodValue());
+ }
+ else if (StringUtils.equalsIgnoreCase(LABEL_URI, labelKey)) {
+ labels.put(labelKey, request.getURI().getPath());
+ }
+ }
+
+ return labels;
+ }
+
+ public static String parseHeaderKey(String expression) {
+ return expression.substring(LABEL_HEADER_PREFIX_LEN, expression.length() - 1);
+ }
+
+ public static String parseQueryKey(String expression) {
+ return expression.substring(LABEL_QUERY_PREFIX_LEN, expression.length() - 1);
+ }
+
+ public static String parseCookieKey(String expression) {
+ return expression.substring(LABEL_COOKIE_PREFIX_LEN, expression.length() - 1);
+ }
+
+ public static String getQueryValue(String queryString, String queryKey) {
if (StringUtils.isBlank(queryString)) {
return StringUtils.EMPTY;
}
@@ -145,7 +253,7 @@ public class ExpressionLabelUtils {
return StringUtils.EMPTY;
}
- private static String getCookieValue(Cookie[] cookies, String key) {
+ public static String getCookieValue(Cookie[] cookies, String key) {
if (cookies == null || cookies.length == 0) {
return StringUtils.EMPTY;
}
@@ -157,7 +265,7 @@ public class ExpressionLabelUtils {
return StringUtils.EMPTY;
}
- private static String getHeaderValue(ServerHttpRequest request, String key) {
+ public static String getHeaderValue(ServerHttpRequest request, String key) {
String value = request.getHeaders().getFirst(key);
if (value == null) {
return StringUtils.EMPTY;
@@ -165,7 +273,7 @@ public class ExpressionLabelUtils {
return value;
}
- private static String getQueryValue(ServerHttpRequest request, String key) {
+ public static String getQueryValue(ServerHttpRequest request, String key) {
MultiValueMap queries = request.getQueryParams();
if (CollectionUtils.isEmpty(queries)) {
return StringUtils.EMPTY;
@@ -177,11 +285,39 @@ public class ExpressionLabelUtils {
return value;
}
- private static String getCookieValue(ServerHttpRequest request, String key) {
+ public static String getCookieValue(ServerHttpRequest request, String key) {
HttpCookie cookie = request.getCookies().getFirst(key);
if (cookie == null) {
return StringUtils.EMPTY;
}
return cookie.getValue();
}
+
+ public static String getHeaderValue(HttpRequest request, String key) {
+ HttpHeaders headers = request.getHeaders();
+ return headers.getFirst(key);
+ }
+
+ public static String getQueryValue(HttpRequest request, String key) {
+ String query = request.getURI().getQuery();
+ return getQueryValue(query, key);
+ }
+
+ public static String getFirstValue(Map> valueMaps, String key) {
+ if (CollectionUtils.isEmpty(valueMaps)) {
+ return StringUtils.EMPTY;
+ }
+
+ Collection values = valueMaps.get(key);
+
+ if (CollectionUtils.isEmpty(values)) {
+ return StringUtils.EMPTY;
+ }
+
+ for (String value : values) {
+ return value;
+ }
+
+ return StringUtils.EMPTY;
+ }
}
diff --git a/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/ServiceRuleManager.java b/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/ServiceRuleManager.java
index a615c5c80..8b3fb16d4 100644
--- a/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/ServiceRuleManager.java
+++ b/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/ServiceRuleManager.java
@@ -75,7 +75,7 @@ public class ServiceRuleManager {
return null;
}
- public List getServiceRouterRule(String namespace, String sourceService, String dstService) {
+ public List getServiceRouterRule(String namespace, String sourceService, String dstService) {
Set routerKeys = new HashSet<>();
ServiceEventKey dstSvcEventKey = new ServiceEventKey(new ServiceKey(namespace, dstService),
@@ -92,20 +92,23 @@ public class ServiceRuleManager {
ResourcesResponse resourcesResponse = BaseFlow
.syncGetResources(sdkContext.getExtensions(), true, svcKeysProvider, controlParam);
- List rules = new ArrayList<>();
+ List rules = new ArrayList<>();
+
+ //get source service outbound rules.
ServiceRule sourceServiceRule = resourcesResponse.getServiceRule(srcSvcEventKey);
if (sourceServiceRule != null) {
Object rule = sourceServiceRule.getRule();
if (rule instanceof RoutingProto.Routing) {
- rules.add((RoutingProto.Routing) rule);
+ rules.addAll(((RoutingProto.Routing) rule).getOutboundsList());
}
}
+ //get peer service inbound rules.
ServiceRule dstServiceRule = resourcesResponse.getServiceRule(dstSvcEventKey);
if (dstServiceRule != null) {
Object rule = dstServiceRule.getRule();
if (rule instanceof RoutingProto.Routing) {
- rules.add((RoutingProto.Routing) rule);
+ rules.addAll(((RoutingProto.Routing) rule).getInboundsList());
}
}