From d4c8fff31ab0eeca32cd33f2f100bd8e1cac0f8b Mon Sep 17 00:00:00 2001 From: shedfreewu <49236872+shedfreewu@users.noreply.github.com> Date: Tue, 26 Mar 2024 16:53:32 +0800 Subject: [PATCH] feat: support lane router (#1250) --- CHANGELOG.md | 3 +- .../pom.xml | 24 +++ .../MetadataTransferAutoConfiguration.java | 70 +++------ .../DecodeTransferMetadataReactiveFilter.java | 23 +-- .../DecodeTransferMetadataServletFilter.java | 21 +-- ...codeTransferMedataFeignEnhancedPlugin.java | 140 ++++++++++++++++++ .../EncodeTransferMedataFeignInterceptor.java | 102 ------------- ...sferMedataRestTemplateEnhancedPlugin.java} | 63 ++++---- ...ncodeTransferMedataScgEnhancedPlugin.java} | 62 +++++--- ...ransferMedataWebClientEnhancedPlugin.java} | 58 +++++--- ...deTransferMetadataZuulEnhancedPlugin.java} | 67 ++++----- .../provider/ReactiveMetadataProvider.java | 66 +++++++++ .../provider/ServletMetadataProvider.java | 67 +++++++++ ...MetadataTransferAutoConfigurationTest.java | 52 ++----- ...odeTransferMedataFeignInterceptorTest.java | 2 +- ...sferMedataRestTemplateInterceptorTest.java | 50 ++++++- .../EncodeTransferMedataScgFilterTest.java | 134 +++++++++++++---- ...codeTransferMedataWebClientFilterTest.java | 2 +- .../EncodeTransferMetadataZuulFilterTest.java | 35 ++++- .../provider/MetadataProviderTest.java | 135 +++++++++++++++++ .../pom.xml | 4 + .../cloud/common/constant/OrderConstant.java | 19 --- .../metadata/MetadataContextHolder.java | 10 +- .../cloud/common/util/ReflectionUtils.java | 16 ++ .../tencent/cloud/common/util/UrlUtils.java | 78 ++++++++++ .../expresstion/ExpressionLabelUtils.java | 10 +- .../ServletExpressionLabelUtils.java | 8 +- .../SpringWebExpressionLabelUtils.java | 20 ++- .../metadata/MetadataContextHolderTest.java | 2 +- .../cloud/common/util/UrlUtilsTest.java | 68 +++++++++ .../callee/QuickstartCalleeController.java | 22 +++ .../loadbalancer/PolarisLoadBalancer.java | 4 +- .../feign/EnhancedFeignClient.java | 1 + .../plugin/EnhancedPluginContext.java | 10 ++ .../plugin/PluginOrderConstant.java | 14 ++ .../EnhancedRestTemplateInterceptor.java | 1 + .../scg/EnhancedGatewayGlobalFilter.java | 12 +- ...hancedWebClientExchangeFilterFunction.java | 14 +- .../zuul/EnhancedPreZuulFilter.java | 1 + 39 files changed, 1070 insertions(+), 420 deletions(-) create mode 100644 spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/EncodeTransferMedataFeignEnhancedPlugin.java delete mode 100644 spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/EncodeTransferMedataFeignInterceptor.java rename spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/{EncodeTransferMedataRestTemplateInterceptor.java => EncodeTransferMedataRestTemplateEnhancedPlugin.java} (60%) rename spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/{EncodeTransferMedataScgFilter.java => EncodeTransferMedataScgEnhancedPlugin.java} (58%) rename spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/{EncodeTransferMedataWebClientFilter.java => EncodeTransferMedataWebClientEnhancedPlugin.java} (57%) rename spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/{EncodeTransferMetadataZuulFilter.java => EncodeTransferMetadataZuulEnhancedPlugin.java} (56%) create mode 100644 spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/provider/ReactiveMetadataProvider.java create mode 100644 spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/provider/ServletMetadataProvider.java create mode 100644 spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/provider/MetadataProviderTest.java create mode 100644 spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/UrlUtils.java create mode 100644 spring-cloud-tencent-commons/src/test/java/com/tencent/cloud/common/util/UrlUtilsTest.java diff --git a/CHANGELOG.md b/CHANGELOG.md index dc61a27f..ac7c92ba 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,4 +3,5 @@ - [feat: support lossless register and deregister at #977](https://github.com/Tencent/spring-cloud-tencent/pull/1242) - [feat: PolarisServiceRegistry#deregister support idempotency.](https://github.com/Tencent/spring-cloud-tencent/pull/1243) -- [feat: SCT元数据管理能力与polaris-java元数据管理能力进行下沉及整合](https://github.com/Tencent/spring-cloud-tencent/pull/1249) \ No newline at end of file +- [feat: SCT元数据管理能力与polaris-java元数据管理能力进行下沉及整合](https://github.com/Tencent/spring-cloud-tencent/pull/1249) +- [feat: support lane router](https://github.com/Tencent/spring-cloud-tencent/pull/1250) \ No newline at end of file diff --git a/spring-cloud-starter-tencent-metadata-transfer/pom.xml b/spring-cloud-starter-tencent-metadata-transfer/pom.xml index ad4714f7..35b783da 100644 --- a/spring-cloud-starter-tencent-metadata-transfer/pom.xml +++ b/spring-cloud-starter-tencent-metadata-transfer/pom.xml @@ -19,6 +19,12 @@ com.tencent.cloud spring-cloud-tencent-commons + + + com.tencent.cloud + spring-cloud-tencent-rpc-enhancement + + @@ -56,6 +62,24 @@ spring-cloud-starter-netflix-ribbon test + + + com.tencent.polaris + polaris-test-mock-discovery + test + + + + com.tencent.polaris + polaris-test-common + test + + + + org.mockito + mockito-inline + test + diff --git a/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/config/MetadataTransferAutoConfiguration.java b/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/config/MetadataTransferAutoConfiguration.java index bbb03328..b9b44089 100644 --- a/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/config/MetadataTransferAutoConfiguration.java +++ b/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/config/MetadataTransferAutoConfiguration.java @@ -18,31 +18,21 @@ package com.tencent.cloud.metadata.config; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -import com.netflix.zuul.ZuulFilter; import com.tencent.cloud.common.constant.OrderConstant; import com.tencent.cloud.metadata.core.DecodeTransferMetadataReactiveFilter; import com.tencent.cloud.metadata.core.DecodeTransferMetadataServletFilter; -import com.tencent.cloud.metadata.core.EncodeTransferMedataFeignInterceptor; -import com.tencent.cloud.metadata.core.EncodeTransferMedataRestTemplateInterceptor; -import com.tencent.cloud.metadata.core.EncodeTransferMedataScgFilter; -import com.tencent.cloud.metadata.core.EncodeTransferMedataWebClientFilter; -import com.tencent.cloud.metadata.core.EncodeTransferMetadataZuulFilter; - -import org.springframework.beans.factory.SmartInitializingSingleton; -import org.springframework.beans.factory.annotation.Autowired; +import com.tencent.cloud.metadata.core.EncodeTransferMedataFeignEnhancedPlugin; +import com.tencent.cloud.metadata.core.EncodeTransferMedataRestTemplateEnhancedPlugin; +import com.tencent.cloud.metadata.core.EncodeTransferMedataScgEnhancedPlugin; +import com.tencent.cloud.metadata.core.EncodeTransferMedataWebClientEnhancedPlugin; +import com.tencent.cloud.metadata.core.EncodeTransferMetadataZuulEnhancedPlugin; + import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication; import org.springframework.boot.web.servlet.FilterRegistrationBean; -import org.springframework.cloud.gateway.filter.GlobalFilter; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.http.client.ClientHttpRequestInterceptor; -import org.springframework.web.client.RestTemplate; -import org.springframework.web.reactive.function.client.WebClient; import static javax.servlet.DispatcherType.ASYNC; import static javax.servlet.DispatcherType.ERROR; @@ -100,11 +90,12 @@ public class MetadataTransferAutoConfiguration { */ @Configuration(proxyBeanMethods = false) @ConditionalOnClass(name = "com.netflix.zuul.http.ZuulServlet") + @ConditionalOnProperty(value = "spring.cloud.tencent.rpc-enhancement.enabled", havingValue = "true", matchIfMissing = true) protected static class MetadataTransferZuulFilterConfig { @Bean - public ZuulFilter encodeTransferMetadataZuulFilter() { - return new EncodeTransferMetadataZuulFilter(); + public EncodeTransferMetadataZuulEnhancedPlugin encodeTransferMedataZuulEnhancedPlugin() { + return new EncodeTransferMetadataZuulEnhancedPlugin(); } } @@ -114,11 +105,12 @@ public class MetadataTransferAutoConfiguration { */ @Configuration(proxyBeanMethods = false) @ConditionalOnClass(name = "org.springframework.cloud.gateway.filter.GlobalFilter") + @ConditionalOnProperty(value = "spring.cloud.tencent.rpc-enhancement.enabled", havingValue = "true", matchIfMissing = true) protected static class MetadataTransferScgFilterConfig { @Bean - public GlobalFilter encodeTransferMedataScgFilter() { - return new EncodeTransferMedataScgFilter(); + public EncodeTransferMedataScgEnhancedPlugin encodeTransferMedataScgEnhancedPlugin() { + return new EncodeTransferMedataScgEnhancedPlugin(); } } @@ -127,11 +119,12 @@ public class MetadataTransferAutoConfiguration { */ @Configuration(proxyBeanMethods = false) @ConditionalOnClass(name = "feign.Feign") + @ConditionalOnProperty(value = "spring.cloud.tencent.rpc-enhancement.enabled", havingValue = "true", matchIfMissing = true) protected static class MetadataTransferFeignInterceptorConfig { @Bean - public EncodeTransferMedataFeignInterceptor encodeTransferMedataFeignInterceptor() { - return new EncodeTransferMedataFeignInterceptor(); + public EncodeTransferMedataFeignEnhancedPlugin encodeTransferMedataFeignEnhancedPlugin() { + return new EncodeTransferMedataFeignEnhancedPlugin(); } } @@ -140,23 +133,12 @@ public class MetadataTransferAutoConfiguration { */ @Configuration(proxyBeanMethods = false) @ConditionalOnClass(name = "org.springframework.web.client.RestTemplate") + @ConditionalOnProperty(value = "spring.cloud.tencent.rpc-enhancement.enabled", havingValue = "true", matchIfMissing = true) protected static class MetadataTransferRestTemplateConfig { - @Autowired(required = false) - private List restTemplates = Collections.emptyList(); - @Bean - public EncodeTransferMedataRestTemplateInterceptor encodeTransferMedataRestTemplateInterceptor() { - return new EncodeTransferMedataRestTemplateInterceptor(); - } - - @Bean - public SmartInitializingSingleton addEncodeTransferMetadataInterceptorForRestTemplate(EncodeTransferMedataRestTemplateInterceptor interceptor) { - return () -> restTemplates.forEach(restTemplate -> { - List list = new ArrayList<>(restTemplate.getInterceptors()); - list.add(interceptor); - restTemplate.setInterceptors(list); - }); + public EncodeTransferMedataRestTemplateEnhancedPlugin encodeTransferMedataRestTemplateEnhancedPlugin() { + return new EncodeTransferMedataRestTemplateEnhancedPlugin(); } } @@ -165,20 +147,12 @@ public class MetadataTransferAutoConfiguration { */ @Configuration(proxyBeanMethods = false) @ConditionalOnClass(name = "org.springframework.web.reactive.function.client.WebClient") + @ConditionalOnProperty(value = "spring.cloud.tencent.rpc-enhancement.enabled", havingValue = "true", matchIfMissing = true) protected static class MetadataTransferWebClientConfig { - @Autowired(required = false) - private List webClientBuilder = Collections.emptyList(); - - @Bean - public EncodeTransferMedataWebClientFilter encodeTransferMedataWebClientFilter() { - return new EncodeTransferMedataWebClientFilter(); - } @Bean - public SmartInitializingSingleton addEncodeTransferMetadataFilterForWebClient(EncodeTransferMedataWebClientFilter filter) { - return () -> webClientBuilder.forEach(webClient -> { - webClient.filter(filter); - }); + public EncodeTransferMedataWebClientEnhancedPlugin encodeTransferMedataWebClientEnhancedPlugin() { + return new EncodeTransferMedataWebClientEnhancedPlugin(); } } } diff --git a/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/DecodeTransferMetadataReactiveFilter.java b/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/DecodeTransferMetadataReactiveFilter.java index 4268f6e7..e4fd1a2c 100644 --- a/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/DecodeTransferMetadataReactiveFilter.java +++ b/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/DecodeTransferMetadataReactiveFilter.java @@ -18,8 +18,6 @@ package com.tencent.cloud.metadata.core; -import java.io.UnsupportedEncodingException; -import java.net.URLDecoder; import java.util.HashMap; import java.util.Map; @@ -27,6 +25,8 @@ import com.tencent.cloud.common.constant.MetadataConstant; import com.tencent.cloud.common.constant.OrderConstant; import com.tencent.cloud.common.metadata.MetadataContextHolder; import com.tencent.cloud.common.util.JacksonUtils; +import com.tencent.cloud.common.util.UrlUtils; +import com.tencent.cloud.metadata.provider.ReactiveMetadataProvider; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import reactor.core.publisher.Mono; @@ -34,12 +34,10 @@ import reactor.core.publisher.Mono; import org.springframework.core.Ordered; import org.springframework.http.HttpHeaders; import org.springframework.http.server.reactive.ServerHttpRequest; -import org.springframework.util.StringUtils; import org.springframework.web.server.ServerWebExchange; import org.springframework.web.server.WebFilter; import org.springframework.web.server.WebFilterChain; -import static com.tencent.cloud.common.constant.ContextConstant.UTF_8; import static com.tencent.cloud.common.constant.MetadataConstant.HeaderName.CUSTOM_DISPOSABLE_METADATA; import static com.tencent.cloud.common.constant.MetadataConstant.HeaderName.CUSTOM_METADATA; @@ -62,19 +60,16 @@ public class DecodeTransferMetadataReactiveFilter implements WebFilter, Ordered public Mono filter(ServerWebExchange serverWebExchange, WebFilterChain webFilterChain) { // Get metadata string from http header. ServerHttpRequest serverHttpRequest = serverWebExchange.getRequest(); - Map internalTransitiveMetadata = getIntervalMetadata(serverHttpRequest, CUSTOM_METADATA); Map customTransitiveMetadata = CustomTransitiveMetadataResolver.resolve(serverWebExchange); Map mergedTransitiveMetadata = new HashMap<>(); mergedTransitiveMetadata.putAll(internalTransitiveMetadata); mergedTransitiveMetadata.putAll(customTransitiveMetadata); - Map internalDisposableMetadata = getIntervalMetadata(serverHttpRequest, CUSTOM_DISPOSABLE_METADATA); Map mergedDisposableMetadata = new HashMap<>(internalDisposableMetadata); - - MetadataContextHolder.init(mergedTransitiveMetadata, mergedDisposableMetadata); - + ReactiveMetadataProvider metadataProvider = new ReactiveMetadataProvider(serverHttpRequest); + MetadataContextHolder.init(mergedTransitiveMetadata, mergedDisposableMetadata, metadataProvider); // Save to ServerWebExchange. serverWebExchange.getAttributes().put( MetadataConstant.HeaderName.METADATA_CONTEXT, @@ -89,15 +84,7 @@ public class DecodeTransferMetadataReactiveFilter implements WebFilter, Ordered private Map getIntervalMetadata(ServerHttpRequest serverHttpRequest, String headerName) { HttpHeaders httpHeaders = serverHttpRequest.getHeaders(); - String customMetadataStr = httpHeaders.getFirst(headerName); - try { - if (StringUtils.hasText(customMetadataStr)) { - customMetadataStr = URLDecoder.decode(customMetadataStr, UTF_8); - } - } - catch (UnsupportedEncodingException e) { - LOG.error("Runtime system does not support utf-8 coding.", e); - } + String customMetadataStr = UrlUtils.decode(httpHeaders.getFirst(headerName)); LOG.debug("Get upstream metadata string: {}", customMetadataStr); return JacksonUtils.deserialize2Map(customMetadataStr); diff --git a/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/DecodeTransferMetadataServletFilter.java b/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/DecodeTransferMetadataServletFilter.java index e1d26efc..d74ddcd7 100644 --- a/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/DecodeTransferMetadataServletFilter.java +++ b/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/DecodeTransferMetadataServletFilter.java @@ -19,8 +19,6 @@ package com.tencent.cloud.metadata.core; import java.io.IOException; -import java.io.UnsupportedEncodingException; -import java.net.URLDecoder; import java.util.HashMap; import java.util.Map; @@ -32,15 +30,15 @@ import javax.servlet.http.HttpServletResponse; import com.tencent.cloud.common.constant.OrderConstant; import com.tencent.cloud.common.metadata.MetadataContextHolder; import com.tencent.cloud.common.util.JacksonUtils; +import com.tencent.cloud.common.util.UrlUtils; +import com.tencent.cloud.metadata.provider.ServletMetadataProvider; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.core.annotation.Order; import org.springframework.lang.NonNull; -import org.springframework.util.StringUtils; import org.springframework.web.filter.OncePerRequestFilter; -import static com.tencent.cloud.common.constant.ContextConstant.UTF_8; import static com.tencent.cloud.common.constant.MetadataConstant.HeaderName.CUSTOM_DISPOSABLE_METADATA; import static com.tencent.cloud.common.constant.MetadataConstant.HeaderName.CUSTOM_METADATA; @@ -65,11 +63,10 @@ public class DecodeTransferMetadataServletFilter extends OncePerRequestFilter { Map mergedTransitiveMetadata = new HashMap<>(); mergedTransitiveMetadata.putAll(internalTransitiveMetadata); mergedTransitiveMetadata.putAll(customTransitiveMetadata); - Map internalDisposableMetadata = getInternalMetadata(httpServletRequest, CUSTOM_DISPOSABLE_METADATA); Map mergedDisposableMetadata = new HashMap<>(internalDisposableMetadata); - - MetadataContextHolder.init(mergedTransitiveMetadata, mergedDisposableMetadata); + ServletMetadataProvider metadataProvider = new ServletMetadataProvider(httpServletRequest); + MetadataContextHolder.init(mergedTransitiveMetadata, mergedDisposableMetadata, metadataProvider); TransHeadersTransfer.transfer(httpServletRequest); try { @@ -83,15 +80,7 @@ public class DecodeTransferMetadataServletFilter extends OncePerRequestFilter { private Map getInternalMetadata(HttpServletRequest httpServletRequest, String headerName) { // Get custom metadata string from http header. - String customMetadataStr = httpServletRequest.getHeader(headerName); - try { - if (StringUtils.hasText(customMetadataStr)) { - customMetadataStr = URLDecoder.decode(customMetadataStr, UTF_8); - } - } - catch (UnsupportedEncodingException e) { - LOG.error("Runtime system does not support utf-8 coding.", e); - } + String customMetadataStr = UrlUtils.decode(httpServletRequest.getHeader(headerName)); LOG.debug("Get upstream metadata string: {}", customMetadataStr); // create custom metadata. diff --git a/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/EncodeTransferMedataFeignEnhancedPlugin.java b/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/EncodeTransferMedataFeignEnhancedPlugin.java new file mode 100644 index 00000000..ff722edc --- /dev/null +++ b/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/EncodeTransferMedataFeignEnhancedPlugin.java @@ -0,0 +1,140 @@ +/* + * 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.metadata.core; + +import java.util.Arrays; +import java.util.Collection; +import java.util.LinkedHashMap; +import java.util.Map; + +import com.google.common.collect.ImmutableMap; +import com.tencent.cloud.common.metadata.MetadataContext; +import com.tencent.cloud.common.metadata.MetadataContextHolder; +import com.tencent.cloud.common.util.JacksonUtils; +import com.tencent.cloud.common.util.ReflectionUtils; +import com.tencent.cloud.common.util.UrlUtils; +import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPlugin; +import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginContext; +import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginType; +import com.tencent.cloud.rpc.enhancement.plugin.PluginOrderConstant; +import com.tencent.polaris.metadata.core.MessageMetadataContainer; +import com.tencent.polaris.metadata.core.MetadataType; +import feign.Request; + +import org.springframework.util.CollectionUtils; + +import static com.tencent.cloud.common.constant.MetadataConstant.HeaderName.CUSTOM_DISPOSABLE_METADATA; +import static com.tencent.cloud.common.constant.MetadataConstant.HeaderName.CUSTOM_METADATA; + +/** + * Pre EnhancedPlugin for feign to encode transfer metadata. + * + * @author Shedfree Wu + */ +public class EncodeTransferMedataFeignEnhancedPlugin implements EnhancedPlugin { + @Override + public EnhancedPluginType getType() { + return EnhancedPluginType.Client.PRE; + } + + @Override + public void run(EnhancedPluginContext context) throws Throwable { + if (!(context.getOriginRequest() instanceof Request)) { + return; + } + Request request = (Request) context.getOriginRequest(); + + // get metadata of current thread + MetadataContext metadataContext = MetadataContextHolder.get(); + Map customMetadata = metadataContext.getCustomMetadata(); + Map disposableMetadata = metadataContext.getDisposableMetadata(); + Map transHeaders = metadataContext.getTransHeadersKV(); + + MessageMetadataContainer calleeMessageMetadataContainer = metadataContext.getMetadataContainer(MetadataType.MESSAGE, false); + Map calleeTransitiveHeaders = calleeMessageMetadataContainer.getTransitiveHeaders(); + // currently only support transitive header from calleeMessageMetadataContainer + this.buildHeaderMap(request, calleeTransitiveHeaders); + + // build custom disposable metadata request header + this.buildMetadataHeader(request, disposableMetadata, CUSTOM_DISPOSABLE_METADATA); + + // process custom metadata + this.buildMetadataHeader(request, customMetadata, CUSTOM_METADATA); + + // set headers that need to be transmitted from the upstream + this.buildTransmittedHeader(request, transHeaders); + } + + private void buildTransmittedHeader(Request request, Map transHeaders) { + if (!CollectionUtils.isEmpty(transHeaders)) { + Map> headers = getModifiableHeaders(request); + transHeaders.entrySet().stream().forEach(entry -> { + headers.remove(entry.getKey()); + headers.put(entry.getKey(), Arrays.asList(entry.getValue())); + }); + } + } + + /** + * Set metadata into the request header for {@link Request} . + * @param request instance of {@link Request} + * @param metadata metadata map . + * @param headerName target metadata http header name . + */ + private void buildMetadataHeader(Request request, Map metadata, String headerName) { + if (!CollectionUtils.isEmpty(metadata)) { + buildHeaderMap(request, ImmutableMap.of(headerName, JacksonUtils.serialize2Json(metadata))); + } + } + + + /** + * Set headerMap into the request header for {@link Request} . + * @param request instance of {@link Request} + * @param headerMap header map . + */ + private void buildHeaderMap(Request request, Map headerMap) { + if (!CollectionUtils.isEmpty(headerMap)) { + Map> headers = getModifiableHeaders(request); + headerMap.forEach((key, value) -> headers.put(key, Arrays.asList(UrlUtils.encode(value)))); + } + } + + /** + * The value obtained directly from the headers method is an unmodifiable map. + * If the Feign client uses the URL, the original headers are unmodifiable. + * @param request feign request + * @return modifiable headers + */ + private Map> getModifiableHeaders(Request request) { + Map> headers; + headers = (Map>) ReflectionUtils.getFieldValue(request, "headers"); + + if (!(headers instanceof LinkedHashMap)) { + headers = new LinkedHashMap<>(headers); + ReflectionUtils.setFieldValue(request, "headers", headers); + } + return headers; + } + + @Override + public int getOrder() { + return PluginOrderConstant.ClientPluginOrder.CONSUMER_TRANSFER_METADATA_PLUGIN_ORDER; + } +} diff --git a/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/EncodeTransferMedataFeignInterceptor.java b/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/EncodeTransferMedataFeignInterceptor.java deleted file mode 100644 index edbf5f0b..00000000 --- a/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/EncodeTransferMedataFeignInterceptor.java +++ /dev/null @@ -1,102 +0,0 @@ -/* - * 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.metadata.core; - -import java.io.UnsupportedEncodingException; -import java.util.Map; - -import com.tencent.cloud.common.constant.OrderConstant; -import com.tencent.cloud.common.metadata.MetadataContext; -import com.tencent.cloud.common.metadata.MetadataContextHolder; -import com.tencent.cloud.common.util.JacksonUtils; -import feign.RequestInterceptor; -import feign.RequestTemplate; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import org.springframework.core.Ordered; -import org.springframework.util.CollectionUtils; -import org.springframework.web.client.RestTemplate; - -import static com.tencent.cloud.common.constant.ContextConstant.UTF_8; -import static com.tencent.cloud.common.constant.MetadataConstant.HeaderName.CUSTOM_DISPOSABLE_METADATA; -import static com.tencent.cloud.common.constant.MetadataConstant.HeaderName.CUSTOM_METADATA; -import static java.net.URLEncoder.encode; - -/** - * Interceptor used for adding the metadata in http headers from context when web client - * is Feign. - * - * @author Haotian Zhang - */ -public class EncodeTransferMedataFeignInterceptor implements RequestInterceptor, Ordered { - - private static final Logger LOG = LoggerFactory.getLogger(EncodeTransferMedataFeignInterceptor.class); - - @Override - public int getOrder() { - return OrderConstant.Client.Feign.ENCODE_TRANSFER_METADATA_INTERCEPTOR_ORDER; - } - - @Override - public void apply(RequestTemplate requestTemplate) { - // get metadata of current thread - MetadataContext metadataContext = MetadataContextHolder.get(); - Map customMetadata = metadataContext.getCustomMetadata(); - Map disposableMetadata = metadataContext.getDisposableMetadata(); - Map transHeaders = metadataContext.getTransHeadersKV(); - - this.buildMetadataHeader(requestTemplate, disposableMetadata, CUSTOM_DISPOSABLE_METADATA); - - // process custom metadata - this.buildMetadataHeader(requestTemplate, customMetadata, CUSTOM_METADATA); - - // set headers that need to be transmitted from the upstream - this.buildTransmittedHeader(requestTemplate, transHeaders); - } - - private void buildTransmittedHeader(RequestTemplate requestTemplate, Map transHeaders) { - if (!CollectionUtils.isEmpty(transHeaders)) { - transHeaders.entrySet().stream().forEach(entry -> { - requestTemplate.removeHeader(entry.getKey()); - requestTemplate.header(entry.getKey(), entry.getValue()); - }); - } - } - - /** - * Set metadata into the request header for {@link RestTemplate} . - * @param requestTemplate instance of {@link RestTemplate} - * @param metadata metadata map . - * @param headerName target metadata http header name . - */ - private void buildMetadataHeader(RequestTemplate requestTemplate, Map metadata, String headerName) { - if (!CollectionUtils.isEmpty(metadata)) { - String encodedMetadata = JacksonUtils.serialize2Json(metadata); - requestTemplate.removeHeader(headerName); - try { - requestTemplate.header(headerName, encode(encodedMetadata, UTF_8)); - } - catch (UnsupportedEncodingException e) { - LOG.error("Set header failed.", e); - requestTemplate.header(headerName, encodedMetadata); - } - } - } -} diff --git a/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/EncodeTransferMedataRestTemplateInterceptor.java b/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/EncodeTransferMedataRestTemplateEnhancedPlugin.java similarity index 60% rename from spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/EncodeTransferMedataRestTemplateInterceptor.java rename to spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/EncodeTransferMedataRestTemplateEnhancedPlugin.java index cbf4901b..50e42885 100644 --- a/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/EncodeTransferMedataRestTemplateInterceptor.java +++ b/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/EncodeTransferMedataRestTemplateEnhancedPlugin.java @@ -18,49 +18,53 @@ package com.tencent.cloud.metadata.core; -import java.io.IOException; -import java.io.UnsupportedEncodingException; -import java.net.URLEncoder; import java.util.Map; -import com.tencent.cloud.common.constant.OrderConstant; +import com.google.common.collect.ImmutableMap; import com.tencent.cloud.common.metadata.MetadataContext; import com.tencent.cloud.common.metadata.MetadataContextHolder; import com.tencent.cloud.common.util.JacksonUtils; +import com.tencent.cloud.common.util.UrlUtils; +import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPlugin; +import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginContext; +import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginType; +import com.tencent.cloud.rpc.enhancement.plugin.PluginOrderConstant; +import com.tencent.polaris.metadata.core.MessageMetadataContainer; +import com.tencent.polaris.metadata.core.MetadataType; -import org.springframework.core.Ordered; import org.springframework.http.HttpRequest; -import org.springframework.http.client.ClientHttpRequestExecution; -import org.springframework.http.client.ClientHttpRequestInterceptor; -import org.springframework.http.client.ClientHttpResponse; -import org.springframework.lang.NonNull; import org.springframework.util.CollectionUtils; -import static com.tencent.cloud.common.constant.ContextConstant.UTF_8; import static com.tencent.cloud.common.constant.MetadataConstant.HeaderName.CUSTOM_DISPOSABLE_METADATA; import static com.tencent.cloud.common.constant.MetadataConstant.HeaderName.CUSTOM_METADATA; /** - * Interceptor used for adding the metadata in http headers from context when web client - * is RestTemplate. + * Pre EnhancedPlugin for rest template to encode transfer metadata. * - * @author Haotian Zhang + * @author Shedfree Wu */ -public class EncodeTransferMedataRestTemplateInterceptor implements ClientHttpRequestInterceptor, Ordered { - +public class EncodeTransferMedataRestTemplateEnhancedPlugin implements EnhancedPlugin { @Override - public int getOrder() { - return OrderConstant.Client.RestTemplate.ENCODE_TRANSFER_METADATA_INTERCEPTOR_ORDER; + public EnhancedPluginType getType() { + return EnhancedPluginType.Client.PRE; } @Override - public ClientHttpResponse intercept(@NonNull HttpRequest httpRequest, @NonNull byte[] bytes, - @NonNull ClientHttpRequestExecution clientHttpRequestExecution) throws IOException { + public void run(EnhancedPluginContext context) throws Throwable { + if (!(context.getOriginRequest() instanceof HttpRequest)) { + return; + } + HttpRequest httpRequest = (HttpRequest) context.getOriginRequest(); + // get metadata of current thread MetadataContext metadataContext = MetadataContextHolder.get(); Map customMetadata = metadataContext.getCustomMetadata(); Map disposableMetadata = metadataContext.getDisposableMetadata(); Map transHeaders = metadataContext.getTransHeadersKV(); + MessageMetadataContainer calleeMessageMetadataContainer = metadataContext.getMetadataContainer(MetadataType.MESSAGE, false); + Map calleeTransitiveHeaders = calleeMessageMetadataContainer.getTransitiveHeaders(); + // currently only support transitive header from calleeMessageMetadataContainer + this.buildHeaderMap(httpRequest, calleeTransitiveHeaders); // build custom disposable metadata request header this.buildMetadataHeader(httpRequest, disposableMetadata, CUSTOM_DISPOSABLE_METADATA); @@ -70,8 +74,6 @@ public class EncodeTransferMedataRestTemplateInterceptor implements ClientHttpRe // set headers that need to be transmitted from the upstream this.buildTransmittedHeader(httpRequest, transHeaders); - - return clientHttpRequestExecution.execute(httpRequest, bytes); } private void buildTransmittedHeader(HttpRequest request, Map transHeaders) { @@ -82,6 +84,12 @@ public class EncodeTransferMedataRestTemplateInterceptor implements ClientHttpRe } } + private void buildHeaderMap(HttpRequest request, Map headerMap) { + if (!CollectionUtils.isEmpty(headerMap)) { + headerMap.forEach((key, value) -> request.getHeaders().set(key, UrlUtils.encode(value))); + } + } + /** * Set metadata into the request header for {@link HttpRequest} . * @@ -91,13 +99,12 @@ public class EncodeTransferMedataRestTemplateInterceptor implements ClientHttpRe */ private void buildMetadataHeader(HttpRequest request, Map metadata, String headerName) { if (!CollectionUtils.isEmpty(metadata)) { - String encodedMetadata = JacksonUtils.serialize2Json(metadata); - try { - request.getHeaders().set(headerName, URLEncoder.encode(encodedMetadata, UTF_8)); - } - catch (UnsupportedEncodingException e) { - request.getHeaders().set(headerName, encodedMetadata); - } + buildHeaderMap(request, ImmutableMap.of(headerName, JacksonUtils.serialize2Json(metadata))); } } + + @Override + public int getOrder() { + return PluginOrderConstant.ClientPluginOrder.CONSUMER_TRANSFER_METADATA_PLUGIN_ORDER; + } } diff --git a/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/EncodeTransferMedataScgFilter.java b/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/EncodeTransferMedataScgEnhancedPlugin.java similarity index 58% rename from spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/EncodeTransferMedataScgFilter.java rename to spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/EncodeTransferMedataScgEnhancedPlugin.java index 2eacd21a..8c996bbf 100644 --- a/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/EncodeTransferMedataScgFilter.java +++ b/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/EncodeTransferMedataScgEnhancedPlugin.java @@ -18,42 +18,46 @@ package com.tencent.cloud.metadata.core; -import java.io.UnsupportedEncodingException; -import java.net.URLEncoder; import java.util.Map; +import com.google.common.collect.ImmutableMap; import com.tencent.cloud.common.constant.MetadataConstant; -import com.tencent.cloud.common.constant.OrderConstant; import com.tencent.cloud.common.metadata.MetadataContext; import com.tencent.cloud.common.metadata.MetadataContextHolder; import com.tencent.cloud.common.util.JacksonUtils; -import reactor.core.publisher.Mono; +import com.tencent.cloud.common.util.UrlUtils; +import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPlugin; +import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginContext; +import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginType; +import com.tencent.cloud.rpc.enhancement.plugin.PluginOrderConstant; +import com.tencent.polaris.metadata.core.MessageMetadataContainer; +import com.tencent.polaris.metadata.core.MetadataType; -import org.springframework.cloud.gateway.filter.GatewayFilterChain; -import org.springframework.cloud.gateway.filter.GlobalFilter; -import org.springframework.core.Ordered; import org.springframework.http.server.reactive.ServerHttpRequest; import org.springframework.util.CollectionUtils; import org.springframework.web.server.ServerWebExchange; -import static com.tencent.cloud.common.constant.ContextConstant.UTF_8; import static com.tencent.cloud.common.constant.MetadataConstant.HeaderName.CUSTOM_DISPOSABLE_METADATA; import static com.tencent.cloud.common.constant.MetadataConstant.HeaderName.CUSTOM_METADATA; /** - * Scg filter used for writing metadata in HTTP request header. + * Pre EnhancedPlugin for scg to encode transfer metadata. * - * @author Haotian Zhang + * @author Shedfree Wu */ -public class EncodeTransferMedataScgFilter implements GlobalFilter, Ordered { - +public class EncodeTransferMedataScgEnhancedPlugin implements EnhancedPlugin { @Override - public int getOrder() { - return OrderConstant.Client.Scg.ENCODE_TRANSFER_METADATA_FILTER_ORDER; + public EnhancedPluginType getType() { + return EnhancedPluginType.Client.PRE; } @Override - public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) { + public void run(EnhancedPluginContext context) throws Throwable { + if (!(context.getOriginRequest() instanceof ServerWebExchange)) { + return; + } + ServerWebExchange exchange = (ServerWebExchange) context.getOriginRequest(); + // get request builder ServerHttpRequest.Builder builder = exchange.getRequest().mutate(); @@ -66,11 +70,22 @@ public class EncodeTransferMedataScgFilter implements GlobalFilter, Ordered { Map customMetadata = metadataContext.getCustomMetadata(); Map disposableMetadata = metadataContext.getDisposableMetadata(); + MessageMetadataContainer calleeMessageMetadataContainer = metadataContext.getMetadataContainer(MetadataType.MESSAGE, false); + Map calleeTransitiveHeaders = calleeMessageMetadataContainer.getTransitiveHeaders(); + // currently only support transitive header from calleeMessageMetadataContainer + this.buildHeaderMap(builder, calleeTransitiveHeaders); + this.buildMetadataHeader(builder, customMetadata, CUSTOM_METADATA); this.buildMetadataHeader(builder, disposableMetadata, CUSTOM_DISPOSABLE_METADATA); - TransHeadersTransfer.transfer(exchange.getRequest()); - return chain.filter(exchange.mutate().request(builder.build()).build()); + + context.setOriginRequest(exchange.mutate().request(builder.build()).build()); + } + + private void buildHeaderMap(ServerHttpRequest.Builder builder, Map headerMap) { + if (!CollectionUtils.isEmpty(headerMap)) { + headerMap.forEach((key, value) -> builder.header(key, UrlUtils.encode(value))); + } } /** @@ -81,13 +96,12 @@ public class EncodeTransferMedataScgFilter implements GlobalFilter, Ordered { */ private void buildMetadataHeader(ServerHttpRequest.Builder builder, Map metadata, String headerName) { if (!CollectionUtils.isEmpty(metadata)) { - String encodedMetadata = JacksonUtils.serialize2Json(metadata); - try { - builder.header(headerName, URLEncoder.encode(encodedMetadata, UTF_8)); - } - catch (UnsupportedEncodingException e) { - builder.header(headerName, encodedMetadata); - } + buildHeaderMap(builder, ImmutableMap.of(headerName, JacksonUtils.serialize2Json(metadata))); } } + + @Override + public int getOrder() { + return PluginOrderConstant.ClientPluginOrder.CONSUMER_TRANSFER_METADATA_PLUGIN_ORDER; + } } diff --git a/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/EncodeTransferMedataWebClientFilter.java b/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/EncodeTransferMedataWebClientEnhancedPlugin.java similarity index 57% rename from spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/EncodeTransferMedataWebClientFilter.java rename to spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/EncodeTransferMedataWebClientEnhancedPlugin.java index 3547add0..2967a2b4 100644 --- a/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/EncodeTransferMedataWebClientFilter.java +++ b/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/EncodeTransferMedataWebClientEnhancedPlugin.java @@ -18,48 +18,61 @@ package com.tencent.cloud.metadata.core; -import java.io.UnsupportedEncodingException; -import java.net.URLEncoder; import java.util.Map; +import com.google.common.collect.ImmutableMap; import com.tencent.cloud.common.metadata.MetadataContext; import com.tencent.cloud.common.metadata.MetadataContextHolder; import com.tencent.cloud.common.util.JacksonUtils; -import reactor.core.publisher.Mono; +import com.tencent.cloud.common.util.UrlUtils; +import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPlugin; +import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginContext; +import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginType; +import com.tencent.cloud.rpc.enhancement.plugin.PluginOrderConstant; +import com.tencent.polaris.metadata.core.MessageMetadataContainer; +import com.tencent.polaris.metadata.core.MetadataType; import org.springframework.util.CollectionUtils; import org.springframework.web.reactive.function.client.ClientRequest; -import org.springframework.web.reactive.function.client.ClientResponse; -import org.springframework.web.reactive.function.client.ExchangeFilterFunction; -import org.springframework.web.reactive.function.client.ExchangeFunction; -import static com.tencent.cloud.common.constant.ContextConstant.UTF_8; import static com.tencent.cloud.common.constant.MetadataConstant.HeaderName.CUSTOM_DISPOSABLE_METADATA; import static com.tencent.cloud.common.constant.MetadataConstant.HeaderName.CUSTOM_METADATA; /** - * web client filter used for writing metadata in HTTP request header. + * Pre EnhancedPlugin for web client to encode transfer metadata. * - * @author sean yu + * @author Shedfree Wu */ -public class EncodeTransferMedataWebClientFilter implements ExchangeFilterFunction { +public class EncodeTransferMedataWebClientEnhancedPlugin implements EnhancedPlugin { + @Override + public EnhancedPluginType getType() { + return EnhancedPluginType.Client.PRE; + } @Override - public Mono filter(ClientRequest clientRequest, ExchangeFunction next) { + public void run(EnhancedPluginContext context) throws Throwable { + if (!(context.getOriginRequest() instanceof ClientRequest)) { + return; + } + ClientRequest clientRequest = (ClientRequest) context.getOriginRequest(); + MetadataContext metadataContext = MetadataContextHolder.get(); Map customMetadata = metadataContext.getCustomMetadata(); Map disposableMetadata = metadataContext.getDisposableMetadata(); Map transHeaders = metadataContext.getTransHeadersKV(); + MessageMetadataContainer calleeMessageMetadataContainer = metadataContext.getMetadataContainer(MetadataType.MESSAGE, false); + Map calleeTransitiveHeaders = calleeMessageMetadataContainer.getTransitiveHeaders(); ClientRequest.Builder requestBuilder = ClientRequest.from(clientRequest); + // currently only support transitive header from calleeMessageMetadataContainer + this.buildHeaderMap(requestBuilder, calleeTransitiveHeaders); + this.buildMetadataHeader(requestBuilder, customMetadata, CUSTOM_METADATA); this.buildMetadataHeader(requestBuilder, disposableMetadata, CUSTOM_DISPOSABLE_METADATA); this.buildTransmittedHeader(requestBuilder, transHeaders); - ClientRequest request = requestBuilder.build(); - - return next.exchange(request); + context.setOriginRequest(requestBuilder.build()); } private void buildTransmittedHeader(ClientRequest.Builder requestBuilder, Map transHeaders) { @@ -68,6 +81,11 @@ public class EncodeTransferMedataWebClientFilter implements ExchangeFilterFuncti } } + private void buildHeaderMap(ClientRequest.Builder requestBuilder, Map headerMap) { + if (!CollectionUtils.isEmpty(headerMap)) { + headerMap.forEach((key, value) -> requestBuilder.header(key, UrlUtils.encode(value))); + } + } /** * Set metadata into the request header for {@link ClientRequest} . @@ -77,14 +95,12 @@ public class EncodeTransferMedataWebClientFilter implements ExchangeFilterFuncti */ private void buildMetadataHeader(ClientRequest.Builder requestBuilder, Map metadata, String headerName) { if (!CollectionUtils.isEmpty(metadata)) { - String encodedMetadata = JacksonUtils.serialize2Json(metadata); - try { - requestBuilder.header(headerName, URLEncoder.encode(encodedMetadata, UTF_8)); - } - catch (UnsupportedEncodingException e) { - requestBuilder.header(headerName, encodedMetadata); - } + buildHeaderMap(requestBuilder, ImmutableMap.of(headerName, JacksonUtils.serialize2Json(metadata))); } } + @Override + public int getOrder() { + return PluginOrderConstant.ClientPluginOrder.CONSUMER_TRANSFER_METADATA_PLUGIN_ORDER; + } } diff --git a/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/EncodeTransferMetadataZuulFilter.java b/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/EncodeTransferMetadataZuulEnhancedPlugin.java similarity index 56% rename from spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/EncodeTransferMetadataZuulFilter.java rename to spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/EncodeTransferMetadataZuulEnhancedPlugin.java index 6aa2a1e0..c1957bda 100644 --- a/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/EncodeTransferMetadataZuulFilter.java +++ b/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/EncodeTransferMetadataZuulEnhancedPlugin.java @@ -18,63 +18,65 @@ package com.tencent.cloud.metadata.core; -import java.io.UnsupportedEncodingException; -import java.net.URLEncoder; import java.util.Map; -import com.netflix.zuul.ZuulFilter; +import com.google.common.collect.ImmutableMap; import com.netflix.zuul.context.RequestContext; -import com.tencent.cloud.common.constant.OrderConstant; import com.tencent.cloud.common.metadata.MetadataContext; import com.tencent.cloud.common.metadata.MetadataContextHolder; import com.tencent.cloud.common.util.JacksonUtils; +import com.tencent.cloud.common.util.UrlUtils; +import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPlugin; +import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginContext; +import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginType; +import com.tencent.cloud.rpc.enhancement.plugin.PluginOrderConstant; +import com.tencent.polaris.metadata.core.MessageMetadataContainer; +import com.tencent.polaris.metadata.core.MetadataType; import org.springframework.util.CollectionUtils; -import static com.tencent.cloud.common.constant.ContextConstant.UTF_8; import static com.tencent.cloud.common.constant.MetadataConstant.HeaderName.CUSTOM_DISPOSABLE_METADATA; import static com.tencent.cloud.common.constant.MetadataConstant.HeaderName.CUSTOM_METADATA; -import static org.springframework.cloud.netflix.zuul.filters.support.FilterConstants.ROUTE_TYPE; /** - * Zuul filter used for writing metadata in HTTP request header. + * Pre EnhancedPlugin for zuul to encode transfer metadata. * - * @author Haotian Zhang + * @author Shedfree Wu */ -public class EncodeTransferMetadataZuulFilter extends ZuulFilter { - - @Override - public String filterType() { - return ROUTE_TYPE; - } - - @Override - public int filterOrder() { - return OrderConstant.Client.Zuul.ENCODE_TRANSFER_METADATA_FILTER_ORDER; - } - +public class EncodeTransferMetadataZuulEnhancedPlugin implements EnhancedPlugin { @Override - public boolean shouldFilter() { - return true; + public EnhancedPluginType getType() { + return EnhancedPluginType.Client.PRE; } @Override - public Object run() { - // get request context - RequestContext requestContext = RequestContext.getCurrentContext(); + public void run(EnhancedPluginContext context) throws Throwable { + if (!(context.getOriginRequest() instanceof RequestContext)) { + return; + } + RequestContext requestContext = (RequestContext) context.getOriginRequest(); // get metadata of current thread MetadataContext metadataContext = MetadataContextHolder.get(); Map customMetadata = metadataContext.getCustomMetadata(); Map disposableMetadata = metadataContext.getDisposableMetadata(); + MessageMetadataContainer calleeMessageMetadataContainer = metadataContext.getMetadataContainer(MetadataType.MESSAGE, false); + Map calleeTransitiveHeaders = calleeMessageMetadataContainer.getTransitiveHeaders(); + // currently only support transitive header from calleeMessageMetadataContainer + this.buildHeaderMap(requestContext, calleeTransitiveHeaders); // Rebuild Metadata Header this.buildMetadataHeader(requestContext, customMetadata, CUSTOM_METADATA); this.buildMetadataHeader(requestContext, disposableMetadata, CUSTOM_DISPOSABLE_METADATA); TransHeadersTransfer.transfer(requestContext.getRequest()); - return null; + } + + private void buildHeaderMap(RequestContext context, Map headerMap) { + if (!CollectionUtils.isEmpty(headerMap)) { + headerMap.forEach((key, value) -> context.addZuulRequestHeader(key, UrlUtils.encode(value))); + } } /** @@ -86,13 +88,12 @@ public class EncodeTransferMetadataZuulFilter extends ZuulFilter { */ private void buildMetadataHeader(RequestContext context, Map metadata, String headerName) { if (!CollectionUtils.isEmpty(metadata)) { - String encodedMetadata = JacksonUtils.serialize2Json(metadata); - try { - context.addZuulRequestHeader(headerName, URLEncoder.encode(encodedMetadata, UTF_8)); - } - catch (UnsupportedEncodingException e) { - context.addZuulRequestHeader(headerName, encodedMetadata); - } + buildHeaderMap(context, ImmutableMap.of(headerName, JacksonUtils.serialize2Json(metadata))); } } + + @Override + public int getOrder() { + return PluginOrderConstant.ClientPluginOrder.CONSUMER_TRANSFER_METADATA_PLUGIN_ORDER; + } } diff --git a/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/provider/ReactiveMetadataProvider.java b/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/provider/ReactiveMetadataProvider.java new file mode 100644 index 00000000..7eb2dc1c --- /dev/null +++ b/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/provider/ReactiveMetadataProvider.java @@ -0,0 +1,66 @@ +/* + * 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.metadata.provider; + +import com.tencent.cloud.common.util.UrlUtils; +import com.tencent.cloud.common.util.expresstion.SpringWebExpressionLabelUtils; +import com.tencent.polaris.metadata.core.MessageMetadataContainer; +import com.tencent.polaris.metadata.core.MetadataProvider; + +import org.springframework.http.server.reactive.ServerHttpRequest; + +/** + * MetadataProvider used for Reactive. + * + * @author Shedfree Wu + */ +public class ReactiveMetadataProvider implements MetadataProvider { + + private ServerHttpRequest serverHttpRequest; + + public ReactiveMetadataProvider(ServerHttpRequest serverHttpRequest) { + this.serverHttpRequest = serverHttpRequest; + } + + @Override + public String getRawMetadataStringValue(String key) { + switch (key) { + case MessageMetadataContainer.LABEL_KEY_METHOD: + return serverHttpRequest.getMethodValue(); + case MessageMetadataContainer.LABEL_KEY_PATH: + return UrlUtils.decode(serverHttpRequest.getPath().toString()); + default: + return null; + } + } + + @Override + public String getRawMetadataMapValue(String key, String mapKey) { + switch (key) { + case MessageMetadataContainer.LABEL_MAP_KEY_HEADER: + return UrlUtils.decode(SpringWebExpressionLabelUtils.getHeaderValue(serverHttpRequest, mapKey, null)); + case MessageMetadataContainer.LABEL_MAP_KEY_COOKIE: + return UrlUtils.decode(SpringWebExpressionLabelUtils.getCookieValue(serverHttpRequest, mapKey, null)); + case MessageMetadataContainer.LABEL_MAP_KEY_QUERY: + return UrlUtils.decode(SpringWebExpressionLabelUtils.getQueryValue(serverHttpRequest, mapKey, null)); + default: + return null; + } + } +} diff --git a/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/provider/ServletMetadataProvider.java b/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/provider/ServletMetadataProvider.java new file mode 100644 index 00000000..f06df5e1 --- /dev/null +++ b/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/provider/ServletMetadataProvider.java @@ -0,0 +1,67 @@ +/* + * 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.metadata.provider; + +import javax.servlet.http.HttpServletRequest; + +import com.tencent.cloud.common.util.UrlUtils; +import com.tencent.cloud.common.util.expresstion.ExpressionLabelUtils; +import com.tencent.cloud.common.util.expresstion.ServletExpressionLabelUtils; +import com.tencent.polaris.metadata.core.MessageMetadataContainer; +import com.tencent.polaris.metadata.core.MetadataProvider; + +/** + * MetadataProvider used for Servlet. + * + * @author Shedfree Wu + */ +public class ServletMetadataProvider implements MetadataProvider { + + private HttpServletRequest httpServletRequest; + + public ServletMetadataProvider(HttpServletRequest httpServletRequest) { + this.httpServletRequest = httpServletRequest; + } + + @Override + public String getRawMetadataStringValue(String key) { + switch (key) { + case MessageMetadataContainer.LABEL_KEY_METHOD: + return httpServletRequest.getMethod(); + case MessageMetadataContainer.LABEL_KEY_PATH: + return UrlUtils.decode(httpServletRequest.getRequestURI()); + default: + return null; + } + } + + @Override + public String getRawMetadataMapValue(String key, String mapKey) { + switch (key) { + case MessageMetadataContainer.LABEL_MAP_KEY_HEADER: + return UrlUtils.decode(httpServletRequest.getHeader(mapKey)); + case MessageMetadataContainer.LABEL_MAP_KEY_COOKIE: + return UrlUtils.decode(ServletExpressionLabelUtils.getCookieValue(httpServletRequest.getCookies(), mapKey, null)); + case MessageMetadataContainer.LABEL_MAP_KEY_QUERY: + return UrlUtils.decode(ExpressionLabelUtils.getQueryValue(httpServletRequest.getQueryString(), mapKey, null)); + default: + return null; + } + } +} diff --git a/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/config/MetadataTransferAutoConfigurationTest.java b/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/config/MetadataTransferAutoConfigurationTest.java index cd23e761..c6111119 100644 --- a/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/config/MetadataTransferAutoConfigurationTest.java +++ b/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/config/MetadataTransferAutoConfigurationTest.java @@ -18,25 +18,17 @@ package com.tencent.cloud.metadata.config; -import java.util.Arrays; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.stream.Collectors; - -import com.tencent.cloud.metadata.core.EncodeTransferMedataFeignInterceptor; -import com.tencent.cloud.metadata.core.EncodeTransferMedataRestTemplateInterceptor; -import com.tencent.cloud.metadata.core.EncodeTransferMedataWebClientFilter; +import com.tencent.cloud.metadata.core.EncodeTransferMedataFeignEnhancedPlugin; +import com.tencent.cloud.metadata.core.EncodeTransferMedataRestTemplateEnhancedPlugin; +import com.tencent.cloud.metadata.core.EncodeTransferMedataWebClientEnhancedPlugin; import org.junit.jupiter.api.Test; import org.springframework.boot.autoconfigure.AutoConfigurations; import org.springframework.boot.test.context.runner.ApplicationContextRunner; import org.springframework.boot.test.context.runner.ReactiveWebApplicationContextRunner; import org.springframework.cloud.client.loadbalancer.LoadBalanced; -import org.springframework.cloud.gateway.filter.GlobalFilter; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.http.client.ClientHttpRequestInterceptor; import org.springframework.web.client.RestTemplate; import static org.assertj.core.api.Assertions.assertThat; @@ -59,35 +51,10 @@ public class MetadataTransferAutoConfigurationTest { this.applicationContextRunner.withConfiguration(AutoConfigurations.of(MetadataTransferAutoConfiguration.class)) .run(context -> { assertThat(context).hasSingleBean(MetadataTransferAutoConfiguration.MetadataTransferFeignInterceptorConfig.class); - assertThat(context).hasSingleBean(EncodeTransferMedataFeignInterceptor.class); + assertThat(context).hasSingleBean(EncodeTransferMedataFeignEnhancedPlugin.class); + assertThat(context).hasSingleBean(EncodeTransferMedataRestTemplateEnhancedPlugin.class); assertThat(context).hasSingleBean(MetadataTransferAutoConfiguration.MetadataTransferRestTemplateConfig.class); - assertThat(context).hasSingleBean(EncodeTransferMedataRestTemplateInterceptor.class); assertThat(context).hasSingleBean(MetadataTransferAutoConfiguration.MetadataTransferScgFilterConfig.class); - assertThat(context).hasSingleBean(GlobalFilter.class); - }); - } - - - @Test - public void test2() { - this.applicationContextRunner - .withConfiguration( - AutoConfigurations.of(MetadataTransferAutoConfiguration.class, RestTemplateConfiguration.class)) - .run(context -> { - assertThat(context).hasSingleBean(EncodeTransferMedataFeignInterceptor.class); - EncodeTransferMedataRestTemplateInterceptor encodeTransferMedataRestTemplateInterceptor = context.getBean(EncodeTransferMedataRestTemplateInterceptor.class); - Map restTemplateMap = context.getBeansOfType(RestTemplate.class); - assertThat(restTemplateMap.size()).isEqualTo(2); - for (String beanName : Arrays.asList("restTemplate", "loadBalancedRestTemplate")) { - RestTemplate restTemplate = restTemplateMap.get(beanName); - assertThat(restTemplate).isNotNull(); - List encodeTransferMedataFeignInterceptorList = restTemplate.getInterceptors() - .stream() - .filter(interceptor -> Objects.equals(interceptor, encodeTransferMedataRestTemplateInterceptor)) - .collect(Collectors.toList()); - //EncodeTransferMetadataFeignInterceptor is not added repeatedly - assertThat(encodeTransferMedataFeignInterceptorList.size()).isEqualTo(1); - } }); } @@ -95,16 +62,15 @@ public class MetadataTransferAutoConfigurationTest { * Reactive web application. */ @Test - public void test3() { + public void test2() { this.reactiveWebApplicationContextRunner.withConfiguration(AutoConfigurations.of(MetadataTransferAutoConfiguration.class)) .run(context -> { assertThat(context).hasSingleBean(MetadataTransferAutoConfiguration.MetadataTransferFeignInterceptorConfig.class); - assertThat(context).hasSingleBean(EncodeTransferMedataFeignInterceptor.class); + assertThat(context).hasSingleBean(EncodeTransferMedataFeignEnhancedPlugin.class); assertThat(context).hasSingleBean(MetadataTransferAutoConfiguration.MetadataTransferRestTemplateConfig.class); - assertThat(context).hasSingleBean(EncodeTransferMedataRestTemplateInterceptor.class); + assertThat(context).hasSingleBean(EncodeTransferMedataRestTemplateEnhancedPlugin.class); assertThat(context).hasSingleBean(MetadataTransferAutoConfiguration.MetadataTransferScgFilterConfig.class); - assertThat(context).hasSingleBean(GlobalFilter.class); - assertThat(context).hasSingleBean(EncodeTransferMedataWebClientFilter.class); + assertThat(context).hasSingleBean(EncodeTransferMedataWebClientEnhancedPlugin.class); }); } diff --git a/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/core/EncodeTransferMedataFeignInterceptorTest.java b/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/core/EncodeTransferMedataFeignInterceptorTest.java index df3e883f..e34f4e9a 100644 --- a/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/core/EncodeTransferMedataFeignInterceptorTest.java +++ b/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/core/EncodeTransferMedataFeignInterceptorTest.java @@ -40,7 +40,7 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.DEFINED_PORT; /** - * Test for {@link EncodeTransferMedataFeignInterceptor}. + * Test for {@link EncodeTransferMedataFeignEnhancedPlugin}. * * @author Haotian Zhang */ diff --git a/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/core/EncodeTransferMedataRestTemplateInterceptorTest.java b/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/core/EncodeTransferMedataRestTemplateInterceptorTest.java index 275784bb..b0ce9217 100644 --- a/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/core/EncodeTransferMedataRestTemplateInterceptorTest.java +++ b/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/core/EncodeTransferMedataRestTemplateInterceptorTest.java @@ -17,8 +17,14 @@ package com.tencent.cloud.metadata.core; +import java.net.URI; +import java.util.Arrays; +import java.util.Map; + import com.tencent.cloud.common.metadata.MetadataContext; import com.tencent.cloud.common.metadata.MetadataContextHolder; +import com.tencent.cloud.rpc.enhancement.plugin.DefaultEnhancedPluginRunner; +import com.tencent.cloud.rpc.enhancement.resttemplate.EnhancedRestTemplateInterceptor; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -26,6 +32,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.web.server.LocalServerPort; +import org.springframework.cloud.client.serviceregistry.Registration; import org.springframework.context.annotation.Bean; import org.springframework.http.HttpEntity; import org.springframework.http.HttpHeaders; @@ -39,7 +46,7 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT; /** - * Test for {@link EncodeTransferMedataRestTemplateInterceptor}. + * Test for {@link EncodeTransferMedataRestTemplateEnhancedPlugin}. * * @author Haotian Zhang */ @@ -72,7 +79,13 @@ public class EncodeTransferMedataRestTemplateInterceptorTest { @Bean public RestTemplate restTemplate() { - return new RestTemplate(); + + EncodeTransferMedataRestTemplateEnhancedPlugin plugin = new EncodeTransferMedataRestTemplateEnhancedPlugin(); + EnhancedRestTemplateInterceptor interceptor = new EnhancedRestTemplateInterceptor( + new DefaultEnhancedPluginRunner(Arrays.asList(plugin), new MockRegistration(), null)); + RestTemplate template = new RestTemplate(); + template.setInterceptors(Arrays.asList(interceptor)); + return template; } @RequestMapping("/test") @@ -80,4 +93,37 @@ public class EncodeTransferMedataRestTemplateInterceptorTest { return MetadataContextHolder.get().getContext(MetadataContext.FRAGMENT_TRANSITIVE, "b"); } } + + static class MockRegistration implements Registration { + + @Override + public String getServiceId() { + return "test"; + } + + @Override + public String getHost() { + return "localhost"; + } + + @Override + public int getPort() { + return 0; + } + + @Override + public boolean isSecure() { + return false; + } + + @Override + public URI getUri() { + return null; + } + + @Override + public Map getMetadata() { + return null; + } + } } diff --git a/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/core/EncodeTransferMedataScgFilterTest.java b/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/core/EncodeTransferMedataScgFilterTest.java index 97f55f73..cbc1116b 100644 --- a/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/core/EncodeTransferMedataScgFilterTest.java +++ b/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/core/EncodeTransferMedataScgFilterTest.java @@ -18,59 +18,129 @@ package com.tencent.cloud.metadata.core; -import java.io.UnsupportedEncodingException; -import java.net.URLDecoder; -import java.util.Map; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.Arrays; import com.tencent.cloud.common.constant.MetadataConstant; -import com.tencent.cloud.common.util.JacksonUtils; +import com.tencent.cloud.common.metadata.MetadataContext; +import com.tencent.cloud.common.metadata.MetadataContextHolder; +import com.tencent.cloud.common.metadata.StaticMetadataManager; +import com.tencent.cloud.common.metadata.config.MetadataLocalProperties; +import com.tencent.cloud.common.util.ApplicationContextAwareUtils; +import com.tencent.cloud.rpc.enhancement.plugin.DefaultEnhancedPluginRunner; +import com.tencent.cloud.rpc.enhancement.scg.EnhancedGatewayGlobalFilter; +import org.assertj.core.util.Maps; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.ArgumentCaptor; import org.mockito.Mock; +import org.mockito.MockedStatic; +import org.mockito.Mockito; +import org.mockito.junit.jupiter.MockitoExtension; +import reactor.core.publisher.Mono; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.cloud.client.serviceregistry.Registration; import org.springframework.cloud.gateway.filter.GatewayFilterChain; +import org.springframework.cloud.gateway.route.Route; import org.springframework.context.ApplicationContext; import org.springframework.mock.http.server.reactive.MockServerHttpRequest; import org.springframework.mock.web.server.MockServerWebExchange; -import org.springframework.test.context.junit.jupiter.SpringExtension; +import org.springframework.web.server.ServerWebExchange; -import static com.tencent.cloud.common.constant.ContextConstant.UTF_8; +import static com.tencent.cloud.common.constant.MetadataConstant.HeaderName.CUSTOM_DISPOSABLE_METADATA; +import static com.tencent.cloud.common.constant.MetadataConstant.HeaderName.CUSTOM_METADATA; +import static com.tencent.polaris.test.common.Consts.NAMESPACE_TEST; +import static com.tencent.polaris.test.common.Consts.SERVICE_PROVIDER; import static org.assertj.core.api.Assertions.assertThat; -import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT; +import static org.assertj.core.api.Assertions.assertThatCode; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; +import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR; +import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.GATEWAY_ROUTE_ATTR; /** - * @author quan + * Test for {@link EncodeTransferMedataScgEnhancedPlugin}. + * @author quan, Shedfree Wu */ -@ExtendWith(SpringExtension.class) -@SpringBootTest(webEnvironment = RANDOM_PORT, classes = EncodeTransferMedataScgFilterTest.TestApplication.class, - properties = {"spring.config.location = classpath:application-test.yml", - "spring.main.web-application-type = reactive"}) +@ExtendWith(MockitoExtension.class) public class EncodeTransferMedataScgFilterTest { - @Autowired - private ApplicationContext applicationContext; - + private static MockedStatic mockedApplicationContextAwareUtils; + @Mock + Registration registration; @Mock - private GatewayFilterChain chain; + GatewayFilterChain chain; - @Test - public void testTransitiveMetadataFromApplicationConfig() throws UnsupportedEncodingException { - EncodeTransferMedataScgFilter filter = applicationContext.getBean(EncodeTransferMedataScgFilter.class); - MockServerHttpRequest.BaseBuilder builder = MockServerHttpRequest.get(""); - MockServerWebExchange exchange = MockServerWebExchange.from(builder); - filter.filter(exchange, chain); - String metadataStr = exchange.getRequest().getHeaders().getFirst(MetadataConstant.HeaderName.CUSTOM_METADATA); - String decode = URLDecoder.decode(metadataStr, UTF_8); - Map transitiveMap = JacksonUtils.deserialize2Map(decode); - assertThat(transitiveMap.size()).isEqualTo(1); - assertThat(transitiveMap.get("b")).isEqualTo("2"); + @BeforeAll + static void beforeAll() { + mockedApplicationContextAwareUtils = Mockito.mockStatic(ApplicationContextAwareUtils.class); + mockedApplicationContextAwareUtils.when(() -> ApplicationContextAwareUtils.getProperties(anyString())) + .thenReturn("unit-test"); + ApplicationContext applicationContext = mock(ApplicationContext.class); + MetadataLocalProperties metadataLocalProperties = mock(MetadataLocalProperties.class); + StaticMetadataManager staticMetadataManager = mock(StaticMetadataManager.class); + doReturn(metadataLocalProperties).when(applicationContext).getBean(MetadataLocalProperties.class); + doReturn(staticMetadataManager).when(applicationContext).getBean(StaticMetadataManager.class); + mockedApplicationContextAwareUtils.when(ApplicationContextAwareUtils::getApplicationContext) + .thenReturn(applicationContext); + } + + @AfterAll + static void afterAll() { + mockedApplicationContextAwareUtils.close(); } - @SpringBootApplication - protected static class TestApplication { + @BeforeEach + void setUp() { + MetadataContext.LOCAL_NAMESPACE = NAMESPACE_TEST; + MetadataContext.LOCAL_SERVICE = SERVICE_PROVIDER; + } + + @Test + public void testRun() throws URISyntaxException { + + Route route = mock(Route.class); + URI uri = new URI("http://TEST/"); + doReturn(uri).when(route).getUri(); + + MetadataContext metadataContext = MetadataContextHolder.get(); + metadataContext.setTransitiveMetadata(Maps.newHashMap("t-key", "t-value")); + metadataContext.setDisposableMetadata(Maps.newHashMap("d-key", "d-value")); + + MockServerHttpRequest mockServerHttpRequest = MockServerHttpRequest.get("/test").build(); + + EncodeTransferMedataScgEnhancedPlugin plugin = new EncodeTransferMedataScgEnhancedPlugin(); + plugin.getOrder(); + EnhancedGatewayGlobalFilter filter = new EnhancedGatewayGlobalFilter(new DefaultEnhancedPluginRunner(Arrays.asList(plugin), registration, null)); + filter.getOrder(); + + MockServerWebExchange mockServerWebExchange = MockServerWebExchange.builder(mockServerHttpRequest).build(); + mockServerWebExchange.getAttributes().put(GATEWAY_ROUTE_ATTR, route); + mockServerWebExchange.getAttributes().put(GATEWAY_REQUEST_URL_ATTR, new URI("http://0.0.0.0/")); + mockServerWebExchange.getAttributes().put(MetadataConstant.HeaderName.METADATA_CONTEXT, metadataContext); + doReturn(Mono.empty()).when(chain).filter(any()); + + + filter.filter(mockServerWebExchange, chain).block(); + + + ArgumentCaptor captor = ArgumentCaptor.forClass(ServerWebExchange.class); + // capture the result exchange + Mockito.verify(chain).filter(captor.capture()); + ServerWebExchange filteredExchange = captor.getValue(); + + assertThat(filteredExchange.getRequest().getHeaders().get(CUSTOM_METADATA)).isNotNull(); + assertThat(filteredExchange.getRequest().getHeaders().get(CUSTOM_DISPOSABLE_METADATA)).isNotNull(); + + // test metadataContext init in EnhancedPlugin + mockServerWebExchange.getAttributes().remove(MetadataConstant.HeaderName.METADATA_CONTEXT); + assertThatCode(() -> filter.filter(mockServerWebExchange, chain).block()).doesNotThrowAnyException(); } } diff --git a/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/core/EncodeTransferMedataWebClientFilterTest.java b/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/core/EncodeTransferMedataWebClientFilterTest.java index 85c8b2d3..fe7c30d2 100644 --- a/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/core/EncodeTransferMedataWebClientFilterTest.java +++ b/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/core/EncodeTransferMedataWebClientFilterTest.java @@ -37,7 +37,7 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT; /** - * Test for {@link EncodeTransferMedataWebClientFilter}. + * Test for {@link EncodeTransferMedataWebClientEnhancedPlugin}. * * @author sean yu */ diff --git a/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/core/EncodeTransferMetadataZuulFilterTest.java b/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/core/EncodeTransferMetadataZuulFilterTest.java index 56895ee2..1c72c5d5 100644 --- a/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/core/EncodeTransferMetadataZuulFilterTest.java +++ b/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/core/EncodeTransferMetadataZuulFilterTest.java @@ -23,9 +23,13 @@ import java.net.URLDecoder; import java.util.Map; import com.netflix.zuul.context.RequestContext; -import com.tencent.cloud.common.constant.MetadataConstant; +import com.netflix.zuul.exception.ZuulException; +import com.tencent.cloud.common.metadata.MetadataContext; +import com.tencent.cloud.common.metadata.MetadataContextHolder; import com.tencent.cloud.common.util.JacksonUtils; +import com.tencent.cloud.rpc.enhancement.zuul.EnhancedPreZuulFilter; import org.assertj.core.api.Assertions; +import org.assertj.core.util.Maps; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -38,12 +42,16 @@ import org.springframework.mock.web.MockMultipartHttpServletRequest; import org.springframework.test.context.junit.jupiter.SpringExtension; import static com.tencent.cloud.common.constant.ContextConstant.UTF_8; +import static com.tencent.cloud.common.constant.MetadataConstant.HeaderName.CUSTOM_DISPOSABLE_METADATA; +import static com.tencent.cloud.common.constant.MetadataConstant.HeaderName.CUSTOM_METADATA; +import static org.assertj.core.api.Assertions.assertThat; import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT; +import static org.springframework.cloud.netflix.zuul.filters.support.FilterConstants.SERVICE_ID_KEY; /** - * Test for {@link EncodeTransferMetadataZuulFilter}. + * Test for {@link EncodeTransferMetadataZuulEnhancedPlugin}. * - * @author quan + * @author quan, Shedfree Wu */ @ExtendWith(SpringExtension.class) @SpringBootTest(webEnvironment = RANDOM_PORT, @@ -64,17 +72,30 @@ public class EncodeTransferMetadataZuulFilterTest { } @Test - public void multiplePartNamesWithMultipleParts() throws UnsupportedEncodingException { - EncodeTransferMetadataZuulFilter filter = applicationContext.getBean(EncodeTransferMetadataZuulFilter.class); + public void testRun() throws ZuulException, UnsupportedEncodingException { + EnhancedPreZuulFilter filter = applicationContext.getBean(EnhancedPreZuulFilter.class); + RequestContext context = RequestContext.getCurrentContext(); + context.set(SERVICE_ID_KEY, "test-service"); + + MetadataContext metadataContext = MetadataContextHolder.get(); + metadataContext.setTransitiveMetadata(Maps.newHashMap("t-key", "t-value")); + metadataContext.setDisposableMetadata(Maps.newHashMap("d-key", "d-value")); filter.run(); + final RequestContext ctx = RequestContext.getCurrentContext(); Map zuulRequestHeaders = ctx.getZuulRequestHeaders(); - String metadata = zuulRequestHeaders.get(MetadataConstant.HeaderName.CUSTOM_METADATA.toLowerCase()); + // convert header to lower case in com.netflix.zuul.context.RequestContext.addZuulRequestHeader + assertThat(zuulRequestHeaders.get(CUSTOM_METADATA.toLowerCase())).isNotNull(); + assertThat(zuulRequestHeaders.get(CUSTOM_DISPOSABLE_METADATA.toLowerCase())).isNotNull(); + + String metadata = zuulRequestHeaders.get(CUSTOM_METADATA.toLowerCase()); + Assertions.assertThat(metadata).isNotNull(); String decode = URLDecoder.decode(metadata, UTF_8); Map transitiveMap = JacksonUtils.deserialize2Map(decode); - Assertions.assertThat(transitiveMap.size()).isEqualTo(1); + // expect {"b":"2","t-key":"t-value"} + Assertions.assertThat(transitiveMap.size()).isEqualTo(2); Assertions.assertThat(transitiveMap.get("b")).isEqualTo("2"); } diff --git a/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/provider/MetadataProviderTest.java b/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/provider/MetadataProviderTest.java new file mode 100644 index 00000000..ff7aedc5 --- /dev/null +++ b/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/provider/MetadataProviderTest.java @@ -0,0 +1,135 @@ +/* + * 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.metadata.provider; + +import com.tencent.cloud.common.util.UrlUtils; +import com.tencent.polaris.metadata.core.MessageMetadataContainer; +import org.junit.Test; + +import org.springframework.http.HttpCookie; +import org.springframework.http.HttpMethod; +import org.springframework.mock.http.server.reactive.MockServerHttpRequest; +import org.springframework.mock.web.MockCookie; +import org.springframework.mock.web.MockHttpServletRequest; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Test for {@link ReactiveMetadataProvider} and {@link ServletMetadataProvider}. + * + * @author quan, Shedfree Wu + */ +public class MetadataProviderTest { + + private static final String notExistKey = "empty"; + + @Test + public void testReactiveMetadataProvider() { + String headerKey1 = "header1"; + String headerKey2 = "header2"; + String headerValue1 = "value1"; + String headerValue2 = "value2/test"; + String queryKey1 = "qk1"; + String queryKey2 = "qk2"; + String queryValue1 = "qv1"; + String queryValue2 = "qv2/test"; + String cookieKey1 = "ck1"; + String cookieKey2 = "ck2"; + String cookieValue1 = "cv1"; + String cookieValue2 = "cv2/test"; + String path = "/echo/test"; + MockServerHttpRequest request = MockServerHttpRequest.get(path) + .header(headerKey1, headerValue1) + .header(headerKey2, UrlUtils.encode(headerValue2)) + .queryParam(queryKey1, queryValue1) + .queryParam(queryKey2, UrlUtils.encode(queryValue2)) + .cookie(new HttpCookie(cookieKey1, cookieValue1)) + .cookie(new HttpCookie(cookieKey2, UrlUtils.encode(cookieValue2))) + .build(); + + ReactiveMetadataProvider reactiveMetadataProvider = new ReactiveMetadataProvider(request); + assertThat(reactiveMetadataProvider.getRawMetadataMapValue(MessageMetadataContainer.LABEL_MAP_KEY_HEADER, headerKey1)).isEqualTo(headerValue1); + assertThat(reactiveMetadataProvider.getRawMetadataMapValue(MessageMetadataContainer.LABEL_MAP_KEY_HEADER, headerKey2)).isEqualTo(headerValue2); + // com.tencent.polaris.metadata.core.manager.ComposeMetadataProvider.getRawMetadataMapValue need return null when key don't exist + assertThat(reactiveMetadataProvider.getRawMetadataMapValue(MessageMetadataContainer.LABEL_MAP_KEY_HEADER, notExistKey)).isNull(); + + assertThat(reactiveMetadataProvider.getRawMetadataMapValue(MessageMetadataContainer.LABEL_MAP_KEY_COOKIE, cookieKey1)).isEqualTo(cookieValue1); + assertThat(reactiveMetadataProvider.getRawMetadataMapValue(MessageMetadataContainer.LABEL_MAP_KEY_COOKIE, cookieKey2)).isEqualTo(cookieValue2); + assertThat(reactiveMetadataProvider.getRawMetadataMapValue(MessageMetadataContainer.LABEL_MAP_KEY_COOKIE, notExistKey)).isNull(); + + assertThat(reactiveMetadataProvider.getRawMetadataMapValue(MessageMetadataContainer.LABEL_MAP_KEY_QUERY, queryKey1)).isEqualTo(queryValue1); + assertThat(reactiveMetadataProvider.getRawMetadataMapValue(MessageMetadataContainer.LABEL_MAP_KEY_QUERY, queryKey2)).isEqualTo(queryValue2); + assertThat(reactiveMetadataProvider.getRawMetadataMapValue(MessageMetadataContainer.LABEL_MAP_KEY_QUERY, notExistKey)).isNull(); + assertThat(reactiveMetadataProvider.getRawMetadataMapValue(notExistKey, queryKey1)).isNull(); + + assertThat(reactiveMetadataProvider.getRawMetadataStringValue(MessageMetadataContainer.LABEL_KEY_METHOD)).isEqualTo("GET"); + assertThat(reactiveMetadataProvider.getRawMetadataStringValue(MessageMetadataContainer.LABEL_KEY_PATH)).isEqualTo(path); + assertThat(reactiveMetadataProvider.getRawMetadataStringValue(notExistKey)).isNull(); + + request = MockServerHttpRequest.get("/echo/" + UrlUtils.decode("a@b")).build(); + reactiveMetadataProvider = new ReactiveMetadataProvider(request); + assertThat(reactiveMetadataProvider.getRawMetadataStringValue(MessageMetadataContainer.LABEL_KEY_PATH)).isEqualTo("/echo/a@b"); + } + + @Test + public void testServletMetadataProvider() { + String headerKey1 = "header1"; + String headerKey2 = "header2"; + String headerValue1 = "value1"; + String headerValue2 = "value2/test"; + String queryKey1 = "qk1"; + String queryKey2 = "qk2"; + String queryValue1 = "qv1"; + String queryValue2 = "qv2/test"; + String cookieKey1 = "ck1"; + String cookieKey2 = "ck2"; + String cookieValue1 = "cv1"; + String cookieValue2 = "cv2/test"; + String path = "/echo/test"; + MockHttpServletRequest request = new MockHttpServletRequest(); + request.addHeader(headerKey1, headerValue1); + request.addHeader(headerKey2, UrlUtils.encode(headerValue2)); + request.setCookies(new MockCookie(cookieKey1, cookieValue1), new MockCookie(cookieKey2, UrlUtils.encode(cookieValue2))); + request.setMethod(HttpMethod.GET.name()); + request.setRequestURI(path); + request.setQueryString(queryKey1 + "=" + queryValue1 + "&" + queryKey2 + "=" + UrlUtils.encode(queryValue2)); + + ServletMetadataProvider servletMetadataProvider = new ServletMetadataProvider(request); + assertThat(servletMetadataProvider.getRawMetadataMapValue(MessageMetadataContainer.LABEL_MAP_KEY_HEADER, headerKey1)).isEqualTo(headerValue1); + assertThat(servletMetadataProvider.getRawMetadataMapValue(MessageMetadataContainer.LABEL_MAP_KEY_HEADER, headerKey2)).isEqualTo(headerValue2); + // com.tencent.polaris.metadata.core.manager.ComposeMetadataProvider.getRawMetadataMapValue need return null when key don't exist + assertThat(servletMetadataProvider.getRawMetadataMapValue(MessageMetadataContainer.LABEL_MAP_KEY_HEADER, notExistKey)).isNull(); + + assertThat(servletMetadataProvider.getRawMetadataMapValue(MessageMetadataContainer.LABEL_MAP_KEY_COOKIE, cookieKey1)).isEqualTo(cookieValue1); + assertThat(servletMetadataProvider.getRawMetadataMapValue(MessageMetadataContainer.LABEL_MAP_KEY_COOKIE, cookieKey2)).isEqualTo(cookieValue2); + assertThat(servletMetadataProvider.getRawMetadataMapValue(MessageMetadataContainer.LABEL_MAP_KEY_COOKIE, notExistKey)).isNull(); + + assertThat(servletMetadataProvider.getRawMetadataMapValue(MessageMetadataContainer.LABEL_MAP_KEY_QUERY, queryKey1)).isEqualTo(queryValue1); + assertThat(servletMetadataProvider.getRawMetadataMapValue(MessageMetadataContainer.LABEL_MAP_KEY_QUERY, queryKey2)).isEqualTo(queryValue2); + assertThat(servletMetadataProvider.getRawMetadataMapValue(MessageMetadataContainer.LABEL_MAP_KEY_QUERY, notExistKey)).isNull(); + assertThat(servletMetadataProvider.getRawMetadataMapValue(notExistKey, queryKey1)).isNull(); + + assertThat(servletMetadataProvider.getRawMetadataStringValue(MessageMetadataContainer.LABEL_KEY_METHOD)).isEqualTo("GET"); + assertThat(servletMetadataProvider.getRawMetadataStringValue(MessageMetadataContainer.LABEL_KEY_PATH)).isEqualTo(path); + assertThat(servletMetadataProvider.getRawMetadataStringValue(notExistKey)).isNull(); + + request.setRequestURI("/echo/" + UrlUtils.decode("a@b")); + assertThat(servletMetadataProvider.getRawMetadataStringValue(MessageMetadataContainer.LABEL_KEY_PATH)).isEqualTo("/echo/a@b"); + } +} diff --git a/spring-cloud-starter-tencent-polaris-router/pom.xml b/spring-cloud-starter-tencent-polaris-router/pom.xml index 56ac0fe5..98ab742b 100644 --- a/spring-cloud-starter-tencent-polaris-router/pom.xml +++ b/spring-cloud-starter-tencent-polaris-router/pom.xml @@ -48,6 +48,10 @@ com.tencent.polaris router-nearby + + com.tencent.polaris + router-lane + diff --git a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/constant/OrderConstant.java b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/constant/OrderConstant.java index be2a3705..2ad9dbb2 100644 --- a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/constant/OrderConstant.java +++ b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/constant/OrderConstant.java @@ -36,10 +36,6 @@ public class OrderConstant { * Order constant for Feign. */ public static class Feign { - /** - * Order of encode transfer metadata interceptor. - */ - public static final int ENCODE_TRANSFER_METADATA_INTERCEPTOR_ORDER = Ordered.LOWEST_PRECEDENCE - 1; /** * Order of encode router label interceptor. @@ -51,10 +47,6 @@ public class OrderConstant { * Order constant for RestTemplate. */ public static class RestTemplate { - /** - * Order of encode transfer metadata interceptor. - */ - public static final int ENCODE_TRANSFER_METADATA_INTERCEPTOR_ORDER = Ordered.LOWEST_PRECEDENCE - 1; /** * Order of encode router label interceptor. @@ -67,12 +59,6 @@ public class OrderConstant { */ public static class Scg { - /** - * Order of encode transfer metadata filter. - * {@link ReactiveLoadBalancerClientFilter}.LOAD_BALANCER_CLIENT_FILTER_ORDER = 10150. - */ - public static final int ENCODE_TRANSFER_METADATA_FILTER_ORDER = 10150 + 1; - /** * Order of enhanced filter. * {@link ReactiveLoadBalancerClientFilter}.LOAD_BALANCER_CLIENT_FILTER_ORDER = 10150. @@ -85,11 +71,6 @@ public class OrderConstant { */ public static class Zuul { - /** - * Order of encode transfer metadata filter. - */ - public static final int ENCODE_TRANSFER_METADATA_FILTER_ORDER = RIBBON_ROUTING_FILTER_ORDER - 1; - /** * Order of enhanced ROUTE filter. */ diff --git a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/metadata/MetadataContextHolder.java b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/metadata/MetadataContextHolder.java index 90e59921..37329ea6 100644 --- a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/metadata/MetadataContextHolder.java +++ b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/metadata/MetadataContextHolder.java @@ -24,7 +24,9 @@ import java.util.Optional; import com.tencent.cloud.common.metadata.config.MetadataLocalProperties; import com.tencent.cloud.common.util.ApplicationContextAwareUtils; +import com.tencent.polaris.metadata.core.MessageMetadataContainer; import com.tencent.polaris.metadata.core.MetadataContainer; +import com.tencent.polaris.metadata.core.MetadataProvider; import com.tencent.polaris.metadata.core.MetadataType; import com.tencent.polaris.metadata.core.TransitiveType; @@ -129,8 +131,10 @@ public final class MetadataContextHolder { * * @param dynamicTransitiveMetadata custom metadata collection * @param dynamicDisposableMetadata custom disposable metadata connection + * @param callerMetadataProvider caller metadata provider */ - public static void init(Map dynamicTransitiveMetadata, Map dynamicDisposableMetadata) { + public static void init(Map dynamicTransitiveMetadata, Map dynamicDisposableMetadata, + MetadataProvider callerMetadataProvider) { com.tencent.polaris.metadata.core.manager.MetadataContextHolder.refresh(MetadataContextHolder::createMetadataManager, metadataManager -> { MetadataContainer metadataContainerUpstream = metadataManager.getMetadataContainer(MetadataType.CUSTOM, false); if (!CollectionUtils.isEmpty(dynamicTransitiveMetadata)) { @@ -144,6 +148,10 @@ public final class MetadataContextHolder { metadataContainerDownstream.putMetadataStringValue(entry.getKey(), entry.getValue(), TransitiveType.DISPOSABLE); } } + if (callerMetadataProvider != null) { + MessageMetadataContainer callerMessageContainer = metadataManager.getMetadataContainer(MetadataType.MESSAGE, true); + callerMessageContainer.setMetadataProvider(callerMetadataProvider); + } }); } diff --git a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/ReflectionUtils.java b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/ReflectionUtils.java index b9f75b94..d822b194 100644 --- a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/ReflectionUtils.java +++ b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/ReflectionUtils.java @@ -68,4 +68,20 @@ public final class ReflectionUtils extends org.springframework.util.ReflectionUt } return null; } + + public static void setFieldValue(Object instance, String fieldName, Object value) { + Field field = org.springframework.util.ReflectionUtils.findField(instance.getClass(), fieldName); + if (field == null) { + return; + } + + field.setAccessible(true); + + try { + setField(field, instance, value); + } + finally { + field.setAccessible(false); + } + } } diff --git a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/UrlUtils.java b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/UrlUtils.java new file mode 100644 index 00000000..6190f33c --- /dev/null +++ b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/UrlUtils.java @@ -0,0 +1,78 @@ +/* + * 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.common.util; + +import java.io.UnsupportedEncodingException; +import java.net.URLDecoder; +import java.net.URLEncoder; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import org.springframework.util.StringUtils; + +import static com.tencent.cloud.common.constant.ContextConstant.UTF_8; + +/** + * Utils for URLDecoder/URLEncoder. + * + * @author Shedfree Wu + */ +public final class UrlUtils { + + private static final Logger LOG = LoggerFactory.getLogger(UrlUtils.class); + + private UrlUtils() { + } + + public static String decode(String s) { + return decode(s, UTF_8); + } + + public static String decode(String s, String enc) { + if (!StringUtils.hasText(s)) { + return s; + } + try { + return URLDecoder.decode(s, enc); + } + catch (UnsupportedEncodingException e) { + LOG.warn("Runtime system does not support {} coding. s:{}, msg:{}", enc, s, e.getMessage()); + // return original string + return s; + } + } + + public static String encode(String s) { + return encode(s, UTF_8); + } + + public static String encode(String s, String enc) { + if (!StringUtils.hasText(s)) { + return s; + } + try { + return URLEncoder.encode(s, enc); + } + catch (UnsupportedEncodingException e) { + LOG.warn("Runtime system does not support {} coding. s:{}, msg:{}", enc, s, e.getMessage()); + // return original string + return s; + } + } +} diff --git a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/expresstion/ExpressionLabelUtils.java b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/expresstion/ExpressionLabelUtils.java index c7029def..9c5e73b9 100644 --- a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/expresstion/ExpressionLabelUtils.java +++ b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/expresstion/ExpressionLabelUtils.java @@ -138,12 +138,16 @@ public final class ExpressionLabelUtils { } public static String getQueryValue(String queryString, String queryKey) { + return getQueryValue(queryString, queryKey, StringUtils.EMPTY); + } + + public static String getQueryValue(String queryString, String queryKey, String defaultValue) { if (StringUtils.isBlank(queryString)) { - return StringUtils.EMPTY; + return defaultValue; } String[] queries = StringUtils.split(queryString, "&"); if (queries == null || queries.length == 0) { - return StringUtils.EMPTY; + return defaultValue; } for (String query : queries) { String[] queryKV = StringUtils.split(query, "="); @@ -151,7 +155,7 @@ public final class ExpressionLabelUtils { return queryKV[1]; } } - return StringUtils.EMPTY; + return defaultValue; } public static String getFirstValue(Map> valueMaps, String key) { diff --git a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/expresstion/ServletExpressionLabelUtils.java b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/expresstion/ServletExpressionLabelUtils.java index a054c8f6..45ad670b 100644 --- a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/expresstion/ServletExpressionLabelUtils.java +++ b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/expresstion/ServletExpressionLabelUtils.java @@ -83,14 +83,18 @@ public final class ServletExpressionLabelUtils { } public static String getCookieValue(Cookie[] cookies, String key) { + return getCookieValue(cookies, key, StringUtils.EMPTY); + } + + public static String getCookieValue(Cookie[] cookies, String key, String defaultValue) { if (cookies == null || cookies.length == 0) { - return StringUtils.EMPTY; + return defaultValue; } for (Cookie cookie : cookies) { if (StringUtils.equals(cookie.getName(), key)) { return cookie.getValue(); } } - return StringUtils.EMPTY; + return defaultValue; } } diff --git a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/expresstion/SpringWebExpressionLabelUtils.java b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/expresstion/SpringWebExpressionLabelUtils.java index b8b1a59a..476aeeec 100644 --- a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/expresstion/SpringWebExpressionLabelUtils.java +++ b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/expresstion/SpringWebExpressionLabelUtils.java @@ -129,29 +129,41 @@ public final class SpringWebExpressionLabelUtils { } public static String getHeaderValue(ServerHttpRequest request, String key) { + return getHeaderValue(request, key, StringUtils.EMPTY); + } + + public static String getHeaderValue(ServerHttpRequest request, String key, String defaultValue) { String value = request.getHeaders().getFirst(key); if (value == null) { - return StringUtils.EMPTY; + return defaultValue; } return value; } public static String getQueryValue(ServerHttpRequest request, String key) { + return getQueryValue(request, key, StringUtils.EMPTY); + } + + public static String getQueryValue(ServerHttpRequest request, String key, String defaultValue) { MultiValueMap queries = request.getQueryParams(); if (CollectionUtils.isEmpty(queries)) { - return StringUtils.EMPTY; + return defaultValue; } String value = queries.getFirst(key); if (value == null) { - return StringUtils.EMPTY; + return defaultValue; } return value; } public static String getCookieValue(ServerHttpRequest request, String key) { + return getCookieValue(request, key, StringUtils.EMPTY); + } + + public static String getCookieValue(ServerHttpRequest request, String key, String defaultValue) { HttpCookie cookie = request.getCookies().getFirst(key); if (cookie == null) { - return StringUtils.EMPTY; + return defaultValue; } return cookie.getValue(); } diff --git a/spring-cloud-tencent-commons/src/test/java/com/tencent/cloud/common/metadata/MetadataContextHolderTest.java b/spring-cloud-tencent-commons/src/test/java/com/tencent/cloud/common/metadata/MetadataContextHolderTest.java index cc992ce1..c2cd05b8 100644 --- a/spring-cloud-tencent-commons/src/test/java/com/tencent/cloud/common/metadata/MetadataContextHolderTest.java +++ b/spring-cloud-tencent-commons/src/test/java/com/tencent/cloud/common/metadata/MetadataContextHolderTest.java @@ -63,7 +63,7 @@ public class MetadataContextHolderTest { customMetadata.put("a", "1"); customMetadata.put("b", "22"); customMetadata.put("c", "3"); - MetadataContextHolder.init(customMetadata, new HashMap<>()); + MetadataContextHolder.init(customMetadata, new HashMap<>(), null); metadataContext = MetadataContextHolder.get(); customMetadata = metadataContext.getTransitiveMetadata(); Assertions.assertThat(customMetadata.get("a")).isEqualTo("1"); diff --git a/spring-cloud-tencent-commons/src/test/java/com/tencent/cloud/common/util/UrlUtilsTest.java b/spring-cloud-tencent-commons/src/test/java/com/tencent/cloud/common/util/UrlUtilsTest.java new file mode 100644 index 00000000..3d77d047 --- /dev/null +++ b/spring-cloud-tencent-commons/src/test/java/com/tencent/cloud/common/util/UrlUtilsTest.java @@ -0,0 +1,68 @@ +/* + * 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.common.util; + +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Utils for {@link UrlUtils}. + * + * @author Shedfree Wu + */ +public class UrlUtilsTest { + + @Test + public void testEncodeDecode1() { + String expectEncodeValue = "a%2Fb"; + String origin = "a/b"; + String encode1 = UrlUtils.encode(origin); + assertThat(expectEncodeValue).isEqualTo(encode1); + // encode twice is different + String encode2 = UrlUtils.encode(encode1); + assertThat(encode1).isNotEqualTo(encode2); + // test decode + assertThat(origin).isEqualTo(UrlUtils.decode(encode1)); + } + + @Test + public void testEncodeDecode2() { + + String origin = null; + String encode1 = UrlUtils.encode(origin); + assertThat(encode1).isNull(); + + origin = ""; + encode1 = UrlUtils.encode(origin); + assertThat(encode1).isEqualTo(origin); + } + + @Test + public void testError() { + String origin = "a/b"; + String encode = UrlUtils.encode(origin, "error-enc"); + assertThat(encode).isEqualTo(origin); + + encode = "a%2Fb"; + String decode = UrlUtils.decode(encode, "error-enc"); + assertThat(decode).isEqualTo(encode); + } + +} diff --git a/spring-cloud-tencent-examples/quickstart-example/quickstart-callee-service-a/src/main/java/com/tencent/cloud/quickstart/callee/QuickstartCalleeController.java b/spring-cloud-tencent-examples/quickstart-example/quickstart-callee-service-a/src/main/java/com/tencent/cloud/quickstart/callee/QuickstartCalleeController.java index 072255d8..ce586e97 100644 --- a/spring-cloud-tencent-examples/quickstart-example/quickstart-callee-service-a/src/main/java/com/tencent/cloud/quickstart/callee/QuickstartCalleeController.java +++ b/spring-cloud-tencent-examples/quickstart-example/quickstart-callee-service-a/src/main/java/com/tencent/cloud/quickstart/callee/QuickstartCalleeController.java @@ -28,6 +28,8 @@ import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestHeader; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; @@ -80,6 +82,26 @@ public class QuickstartCalleeController { return String.format("Quickstart [%s] Service [%s:%s] is called. datasource = [%s].", appName, ip, port, dataSourceProperties); } + /** + * Mock post save value. + * @return true + */ + @PostMapping("/saveValue") + public Boolean saveValue(@RequestParam int value) { + LOG.info("Quickstart [{}] Service [{}:{}] is called. Mock save value = [{}].", appName, ip, port, value); + return true; + } + + /** + * Get path echo of callee. + * @return information of callee + */ + @GetMapping("/path/echo/{param}") + public String pathEcho(@PathVariable String param) { + LOG.info("Quickstart [{}] Service [{}:{}] is called. param = [{}].", appName, ip, port, param); + return String.format("Quickstart [%s] Service [%s:%s] is called. datasource = [%s].", appName, ip, port, param); + } + /** * Get metadata in HTTP header. * diff --git a/spring-cloud-tencent-polaris-loadbalancer/src/main/java/com/tencent/cloud/polaris/loadbalancer/PolarisLoadBalancer.java b/spring-cloud-tencent-polaris-loadbalancer/src/main/java/com/tencent/cloud/polaris/loadbalancer/PolarisLoadBalancer.java index 07335adf..d9b13834 100644 --- a/spring-cloud-tencent-polaris-loadbalancer/src/main/java/com/tencent/cloud/polaris/loadbalancer/PolarisLoadBalancer.java +++ b/spring-cloud-tencent-polaris-loadbalancer/src/main/java/com/tencent/cloud/polaris/loadbalancer/PolarisLoadBalancer.java @@ -76,8 +76,8 @@ public class PolarisLoadBalancer extends DynamicServerListLoadBalancer { @Override public List getReachableServers() { - // Get servers first from the thread context - if (!CollectionUtils.isEmpty(THREAD_CACHE_SERVERS.get())) { + // Get servers first from the thread context. When routers filter all instances, getReachableServersWithoutCache function cannot be executed. + if (THREAD_CACHE_SERVERS.get() != null) { return THREAD_CACHE_SERVERS.get(); } return getReachableServersWithoutCache(); diff --git a/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/feign/EnhancedFeignClient.java b/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/feign/EnhancedFeignClient.java index f50e5df5..ec0e2397 100644 --- a/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/feign/EnhancedFeignClient.java +++ b/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/feign/EnhancedFeignClient.java @@ -67,6 +67,7 @@ public class EnhancedFeignClient implements Client { .url(url) .build(); enhancedPluginContext.setRequest(enhancedRequestContext); + enhancedPluginContext.setOriginRequest(request); enhancedPluginContext.setLocalServiceInstance(pluginRunner.getLocalServiceInstance()); DefaultServiceInstance serviceInstance = new DefaultServiceInstance(request.requestTemplate().feignTarget() diff --git a/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/plugin/EnhancedPluginContext.java b/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/plugin/EnhancedPluginContext.java index 7eb14ae8..e9ef0cc6 100644 --- a/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/plugin/EnhancedPluginContext.java +++ b/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/plugin/EnhancedPluginContext.java @@ -36,6 +36,8 @@ public class EnhancedPluginContext { private static final Logger LOGGER = LoggerFactory.getLogger(EnhancedPluginContext.class); + private Object originRequest; + private EnhancedRequestContext request; private EnhancedResponseContext response; @@ -51,6 +53,14 @@ public class EnhancedPluginContext { */ private ServiceInstance targetServiceInstance; + public Object getOriginRequest() { + return originRequest; + } + + public void setOriginRequest(Object originRequest) { + this.originRequest = originRequest; + } + public EnhancedRequestContext getRequest() { return request; } diff --git a/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/plugin/PluginOrderConstant.java b/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/plugin/PluginOrderConstant.java index 6677dac0..eff88f13 100644 --- a/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/plugin/PluginOrderConstant.java +++ b/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/plugin/PluginOrderConstant.java @@ -44,5 +44,19 @@ public class PluginOrderConstant { * {@link com.tencent.cloud.polaris.circuitbreaker.reporter.ExceptionCircuitBreakerReporter}. */ public static final int CIRCUIT_BREAKER_REPORTER_PLUGIN_ORDER = Ordered.HIGHEST_PRECEDENCE + 2; + + /** + * order for + * {@link com.tencent.cloud.metadata.core.EncodeTransferMedataFeignEnhancedPlugin} + * and + * {@link com.tencent.cloud.metadata.core.EncodeTransferMedataScgEnhancedPlugin} + * and + * {@link com.tencent.cloud.metadata.core.EncodeTransferMedataWebClientEnhancedPlugin} + * and + * {@link com.tencent.cloud.metadata.core.EncodeTransferMedataZuulEnhancedPlugin} + * and + * {@link com.tencent.cloud.metadata.core.EncodeTransferMedataRestTemplateEnhancedPlugin}. + */ + public static final int CONSUMER_TRANSFER_METADATA_PLUGIN_ORDER = Ordered.HIGHEST_PRECEDENCE + 10; } } diff --git a/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/resttemplate/EnhancedRestTemplateInterceptor.java b/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/resttemplate/EnhancedRestTemplateInterceptor.java index c50cbb90..6241ac59 100644 --- a/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/resttemplate/EnhancedRestTemplateInterceptor.java +++ b/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/resttemplate/EnhancedRestTemplateInterceptor.java @@ -58,6 +58,7 @@ public class EnhancedRestTemplateInterceptor implements ClientHttpRequestInterce .url(request.getURI()) .build(); enhancedPluginContext.setRequest(enhancedRequestContext); + enhancedPluginContext.setOriginRequest(request); enhancedPluginContext.setLocalServiceInstance(pluginRunner.getLocalServiceInstance()); enhancedPluginContext.setTargetServiceInstance((ServiceInstance) MetadataContextHolder.get() diff --git a/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/scg/EnhancedGatewayGlobalFilter.java b/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/scg/EnhancedGatewayGlobalFilter.java index f42aff2b..7b65f2e8 100644 --- a/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/scg/EnhancedGatewayGlobalFilter.java +++ b/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/scg/EnhancedGatewayGlobalFilter.java @@ -51,19 +51,21 @@ public class EnhancedGatewayGlobalFilter implements GlobalFilter, Ordered { } @Override - public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) { + public Mono filter(ServerWebExchange originExchange, GatewayFilterChain chain) { EnhancedPluginContext enhancedPluginContext = new EnhancedPluginContext(); EnhancedRequestContext enhancedRequestContext = EnhancedRequestContext.builder() - .httpHeaders(exchange.getRequest().getHeaders()) - .httpMethod(exchange.getRequest().getMethod()) - .url(exchange.getRequest().getURI()) + .httpHeaders(originExchange.getRequest().getHeaders()) + .httpMethod(originExchange.getRequest().getMethod()) + .url(originExchange.getRequest().getURI()) .build(); enhancedPluginContext.setRequest(enhancedRequestContext); + enhancedPluginContext.setOriginRequest(originExchange); // Run pre enhanced plugins. pluginRunner.run(EnhancedPluginType.Client.PRE, enhancedPluginContext); - + // Exchange may be changed in plugin + ServerWebExchange exchange = (ServerWebExchange) enhancedPluginContext.getOriginRequest(); long startTime = System.currentTimeMillis(); return chain.filter(exchange) .doOnSubscribe(v -> { diff --git a/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/webclient/EnhancedWebClientExchangeFilterFunction.java b/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/webclient/EnhancedWebClientExchangeFilterFunction.java index 673cac3d..a215cfe8 100644 --- a/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/webclient/EnhancedWebClientExchangeFilterFunction.java +++ b/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/webclient/EnhancedWebClientExchangeFilterFunction.java @@ -46,23 +46,25 @@ public class EnhancedWebClientExchangeFilterFunction implements ExchangeFilterFu } @Override - public Mono filter(ClientRequest request, ExchangeFunction next) { + public Mono filter(ClientRequest originRequest, ExchangeFunction next) { EnhancedPluginContext enhancedPluginContext = new EnhancedPluginContext(); EnhancedRequestContext enhancedRequestContext = EnhancedRequestContext.builder() - .httpHeaders(request.headers()) - .httpMethod(request.method()) - .url(request.url()) + .httpHeaders(originRequest.headers()) + .httpMethod(originRequest.method()) + .url(originRequest.url()) .build(); enhancedPluginContext.setRequest(enhancedRequestContext); + enhancedPluginContext.setOriginRequest(originRequest); enhancedPluginContext.setLocalServiceInstance(pluginRunner.getLocalServiceInstance()); enhancedPluginContext.setTargetServiceInstance((ServiceInstance) MetadataContextHolder.get() - .getLoadbalancerMetadata().get(LOAD_BALANCER_SERVICE_INSTANCE), request.url()); + .getLoadbalancerMetadata().get(LOAD_BALANCER_SERVICE_INSTANCE), originRequest.url()); // Run post enhanced plugins. pluginRunner.run(EnhancedPluginType.Client.PRE, enhancedPluginContext); - + // request may be changed by plugin + ClientRequest request = (ClientRequest) enhancedPluginContext.getOriginRequest(); long startTime = System.currentTimeMillis(); return next.exchange(request) .doOnSuccess(response -> { diff --git a/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/zuul/EnhancedPreZuulFilter.java b/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/zuul/EnhancedPreZuulFilter.java index 1254209c..094f24f7 100644 --- a/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/zuul/EnhancedPreZuulFilter.java +++ b/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/zuul/EnhancedPreZuulFilter.java @@ -99,6 +99,7 @@ public class EnhancedPreZuulFilter extends ZuulFilter { .build(); enhancedPluginContext.setRequest(enhancedRequestContext); + enhancedPluginContext.setOriginRequest(context); enhancedPluginContext.setLocalServiceInstance(pluginRunner.getLocalServiceInstance()); // Run pre enhanced plugins.