Automatically transmit some headers specified by a environment varaible that directly defines header keys. (#606)

Co-authored-by: Haotian Zhang <928016560@qq.com>
pull/613/head
Wu Daifu 2 years ago committed by GitHub
parent 35458f8b4f
commit dad543e225
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -5,4 +5,5 @@
- [Optimize: remove discovery module useless code](https://github.com/Tencent/spring-cloud-tencent/pull/595)
- [Optimize: remove useless code for rest template router](https://github.com/Tencent/spring-cloud-tencent/pull/601)
- [Optimize: optimize configuration conditional & optimize config data tips](https://github.com/Tencent/spring-cloud-tencent/pull/603)
- [Automatically transmit some headers specified by a environment varaible that directly defines header keys.](https://github.com/Tencent/spring-cloud-tencent/pull/606)
- [Optimize: Maybe remove Chinese characters](https://github.com/Tencent/spring-cloud-tencent/pull/607)

@ -20,8 +20,13 @@ package com.tencent.cloud.metadata.core;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import com.tencent.cloud.common.constant.MetadataConstant;
import com.tencent.cloud.common.metadata.MetadataContextHolder;
@ -33,6 +38,7 @@ 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.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.WebFilter;
@ -41,6 +47,8 @@ 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;
import static com.tencent.cloud.common.metadata.MetadataContext.FRAGMENT_RAW_TRANSHEADERS;
import static com.tencent.cloud.common.metadata.MetadataContext.FRAGMENT_RAW_TRANSHEADERS_KV;
/**
* Filter used for storing the metadata from upstream temporarily when web application is
@ -79,12 +87,41 @@ public class DecodeTransferMetadataReactiveFilter implements WebFilter, Ordered
MetadataConstant.HeaderName.METADATA_CONTEXT,
MetadataContextHolder.get());
setCompleteTransHeaderIntoMC(serverHttpRequest);
return webFilterChain.filter(serverWebExchange)
.doOnError(throwable -> LOG.error("handle metadata[{}] error.",
MetadataContextHolder.get(), throwable))
.doFinally((type) -> MetadataContextHolder.remove());
}
/**
* According to ServerHttpRequest and trans-headers(key list in string type) in metadata, build
* the complete headers(key-value list in map type) into metadata.
*/
private void setCompleteTransHeaderIntoMC(ServerHttpRequest serverHttpRequest) {
// transHeaderMetadata: for example, {"trans-headers" : {"header1;header2;header3":""}}
Map<String, String> transHeaderMetadata = MetadataContextHolder.get()
.getFragmentContext(FRAGMENT_RAW_TRANSHEADERS);
if (!CollectionUtils.isEmpty(transHeaderMetadata)) {
Optional<String> transHeaders = transHeaderMetadata.keySet().stream().findFirst();
String[] transHeaderArray = transHeaders.get().split(";");
HttpHeaders headers = serverHttpRequest.getHeaders();
Set<String> headerKeys = headers.keySet();
Iterator<String> iterator = headerKeys.iterator();
while (iterator.hasNext()) {
String httpHeader = iterator.next();
Arrays.stream(transHeaderArray).forEach(transHeader -> {
if (transHeader.equals(httpHeader)) {
List<String> list = headers.get(httpHeader);
String httpHeaderValue = JacksonUtils.serialize2Json(list);
MetadataContextHolder.get().putContext(FRAGMENT_RAW_TRANSHEADERS_KV, httpHeader, httpHeaderValue);
return;
}
});
}
}
}
private Map<String, String> getIntervalMetadata(ServerHttpRequest serverHttpRequest, String headerName) {
HttpHeaders httpHeaders = serverHttpRequest.getHeaders();
String customMetadataStr = httpHeaders.getFirst(headerName);

@ -21,8 +21,11 @@ package com.tencent.cloud.metadata.core;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
@ -37,12 +40,15 @@ import org.slf4j.LoggerFactory;
import org.springframework.core.annotation.Order;
import org.springframework.lang.NonNull;
import org.springframework.util.CollectionUtils;
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;
import static com.tencent.cloud.common.metadata.MetadataContext.FRAGMENT_RAW_TRANSHEADERS;
import static com.tencent.cloud.common.metadata.MetadataContext.FRAGMENT_RAW_TRANSHEADERS_KV;
/**
* Filter used for storing the metadata from upstream temporarily when web application is
@ -71,9 +77,35 @@ public class DecodeTransferMetadataServletFilter extends OncePerRequestFilter {
MetadataContextHolder.init(mergedTransitiveMetadata, mergedDisposableMetadata);
setCompleteTransHeaderIntoMC(httpServletRequest);
filterChain.doFilter(httpServletRequest, httpServletResponse);
}
/**
* According to HttpServletRequest and trans-headers(key list in string type) in metadata, build
* the complete headers(key-value list in map type) into metadata.
*/
private void setCompleteTransHeaderIntoMC(HttpServletRequest httpServletRequest) {
// transHeaderMetadata: for example, {"trans-headers" : {"header1;header2;header3":""}}
Map<String, String> transHeaderMetadata = MetadataContextHolder.get()
.getFragmentContext(FRAGMENT_RAW_TRANSHEADERS);
if (!CollectionUtils.isEmpty(transHeaderMetadata)) {
Optional<String> transHeaders = transHeaderMetadata.keySet().stream().findFirst();
String[] transHeaderArray = transHeaders.get().split(";");
Enumeration<String> httpHeaders = httpServletRequest.getHeaderNames();
while (httpHeaders.hasMoreElements()) {
String httpHeader = httpHeaders.nextElement();
Arrays.stream(transHeaderArray).forEach(transHeader -> {
if (transHeader.equals(httpHeader)) {
String httpHeaderValue = httpServletRequest.getHeader(httpHeader);
MetadataContextHolder.get().putContext(FRAGMENT_RAW_TRANSHEADERS_KV, httpHeader, httpHeaderValue);
return;
}
});
}
}
}
private Map<String, String> getInternalMetadata(HttpServletRequest httpServletRequest, String headerName) {
// Get custom metadata string from http header.
String customMetadataStr = httpServletRequest.getHeader(headerName);

@ -61,6 +61,7 @@ public class EncodeTransferMedataFeignInterceptor implements RequestInterceptor,
MetadataContext metadataContext = MetadataContextHolder.get();
Map<String, String> customMetadata = metadataContext.getFragmentContext(MetadataContext.FRAGMENT_TRANSITIVE);
Map<String, String> disposableMetadata = metadataContext.getFragmentContext(MetadataContext.FRAGMENT_DISPOSABLE);
Map<String, String> transHeaders = metadataContext.getFragmentContext(MetadataContext.FRAGMENT_RAW_TRANSHEADERS_KV);
// Clean up one-time metadata coming from upstream .
Map<String, String> newestCustomMetadata = new HashMap<>();
@ -71,8 +72,20 @@ public class EncodeTransferMedataFeignInterceptor implements RequestInterceptor,
});
this.buildMetadataHeader(requestTemplate, disposableMetadata, CUSTOM_DISPOSABLE_METADATA);
// process custom metadata finally
// process custom metadata
this.buildMetadataHeader(requestTemplate, newestCustomMetadata, CUSTOM_METADATA);
// set headers that need to be transmitted from the upstream
this.buildTransmittedHeader(requestTemplate, transHeaders);
}
private void buildTransmittedHeader(RequestTemplate requestTemplate, Map<String, String> transHeaders) {
if (!CollectionUtils.isEmpty(transHeaders)) {
transHeaders.entrySet().stream().forEach(entry -> {
requestTemplate.removeHeader(entry.getKey());
requestTemplate.header(entry.getKey(), entry.getValue());
});
}
}
/**

@ -61,6 +61,7 @@ public class EncodeTransferMedataRestTemplateInterceptor implements ClientHttpRe
MetadataContext metadataContext = MetadataContextHolder.get();
Map<String, String> customMetadata = metadataContext.getFragmentContext(MetadataContext.FRAGMENT_TRANSITIVE);
Map<String, String> disposableMetadata = metadataContext.getFragmentContext(MetadataContext.FRAGMENT_DISPOSABLE);
Map<String, String> transHeaders = metadataContext.getFragmentContext(MetadataContext.FRAGMENT_RAW_TRANSHEADERS_KV);
Map<String, String> newestCustomMetadata = new HashMap<>();
customMetadata.forEach((key, value) -> {
@ -74,9 +75,20 @@ public class EncodeTransferMedataRestTemplateInterceptor implements ClientHttpRe
// build custom metadata request header
this.buildMetadataHeader(httpRequest, newestCustomMetadata, CUSTOM_METADATA);
// 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<String, String> transHeaders) {
if (!CollectionUtils.isEmpty(transHeaders)) {
transHeaders.entrySet().stream().forEach(entry -> {
request.getHeaders().set(entry.getKey(), entry.getValue());
});
}
}
/**
* Set metadata into the request header for {@link HttpRequest} .
*

@ -20,8 +20,13 @@ package com.tencent.cloud.metadata.core;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import com.tencent.cloud.common.constant.MetadataConstant;
import com.tencent.cloud.common.metadata.MetadataContext;
@ -32,6 +37,7 @@ import reactor.core.publisher.Mono;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.http.HttpHeaders;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.util.CollectionUtils;
import org.springframework.web.server.ServerWebExchange;
@ -39,6 +45,8 @@ 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.cloud.common.metadata.MetadataContext.FRAGMENT_RAW_TRANSHEADERS;
import static com.tencent.cloud.common.metadata.MetadataContext.FRAGMENT_RAW_TRANSHEADERS_KV;
import static org.springframework.cloud.gateway.filter.ReactiveLoadBalancerClientFilter.LOAD_BALANCER_CLIENT_FILTER_ORDER;
/**
@ -80,9 +88,39 @@ public class EncodeTransferMedataScgFilter implements GlobalFilter, Ordered {
this.buildMetadataHeader(builder, newestCustomMetadata, CUSTOM_METADATA);
this.buildMetadataHeader(builder, disposableMetadata, CUSTOM_DISPOSABLE_METADATA);
setCompleteTransHeaderIntoMC(exchange.getRequest());
return chain.filter(exchange.mutate().request(builder.build()).build());
}
/**
* According to ServerHttpRequest and trans-headers(key list in string type) in metadata, build
* the complete headers(key-value list in map type) into metadata.
*/
private void setCompleteTransHeaderIntoMC(ServerHttpRequest serverHttpRequest) {
// transHeaderMetadata: for example, {"trans-headers" : {"header1;header2;header3":""}}
Map<String, String> transHeaderMetadata = MetadataContextHolder.get()
.getFragmentContext(FRAGMENT_RAW_TRANSHEADERS);
if (!CollectionUtils.isEmpty(transHeaderMetadata)) {
Optional<String> transHeaders = transHeaderMetadata.keySet().stream().findFirst();
String[] transHeaderArray = transHeaders.get().split(";");
HttpHeaders headers = serverHttpRequest.getHeaders();
Set<String> headerKeys = headers.keySet();
Iterator<String> iterator = headerKeys.iterator();
while (iterator.hasNext()) {
String httpHeader = iterator.next();
Arrays.stream(transHeaderArray).forEach(transHeader -> {
if (transHeader.equals(httpHeader)) {
List<String> list = headers.get(httpHeader);
String httpHeaderValue = JacksonUtils.serialize2Json(list);
// for example, {"trans-headers-kv" : {"header1":"v1","header2":"v2"...}}
MetadataContextHolder.get().putContext(FRAGMENT_RAW_TRANSHEADERS_KV, httpHeader, httpHeaderValue);
return;
}
});
}
}
}
/**
* Set metadata into the request header for {@link ServerHttpRequest.Builder} .
* @param builder instance of {@link ServerHttpRequest.Builder}

@ -56,6 +56,16 @@ public class MetadataContext {
*/
public static final String FRAGMENT_UPSTREAM_DISPOSABLE = "upstream-disposable";
/**
* the key of the header(key) list needed to be transmitted from upstream to downstream.
*/
public static final String FRAGMENT_RAW_TRANSHEADERS = "trans-headers";
/**
* the key of the header(key-value) list needed to be transmitted from upstream to downstream.
*/
public static final String FRAGMENT_RAW_TRANSHEADERS_KV = "trans-headers-kv";
private static final Logger LOG = LoggerFactory.getLogger(MetadataContext.class);
/**
* Namespace of local instance.

@ -28,6 +28,7 @@ import com.tencent.cloud.common.util.ApplicationContextAwareUtils;
import org.springframework.util.CollectionUtils;
import static com.tencent.cloud.common.metadata.MetadataContext.FRAGMENT_DISPOSABLE;
import static com.tencent.cloud.common.metadata.MetadataContext.FRAGMENT_RAW_TRANSHEADERS;
import static com.tencent.cloud.common.metadata.MetadataContext.FRAGMENT_TRANSITIVE;
import static com.tencent.cloud.common.metadata.MetadataContext.FRAGMENT_UPSTREAM_DISPOSABLE;
@ -67,6 +68,7 @@ public final class MetadataContextHolder {
MetadataContext metadataContext = new MetadataContext();
metadataContext.putFragmentContext(FRAGMENT_TRANSITIVE, staticMetadataManager.getMergedStaticTransitiveMetadata());
metadataContext.putFragmentContext(FRAGMENT_DISPOSABLE, staticMetadataManager.getMergedStaticDisposableMetadata());
metadataContext.putContext(FRAGMENT_RAW_TRANSHEADERS, staticMetadataManager.getEnvTransHeaderMetadata(), "");
METADATA_CONTEXT.set(metadataContext);

@ -55,6 +55,12 @@ public class StaticMetadataManager {
private static final int ENV_METADATA_PREFIX_LENGTH = ENV_METADATA_PREFIX.length();
private static final String ENV_METADATA_CONTENT_TRANSITIVE = "SCT_METADATA_CONTENT_TRANSITIVE";
private static final String ENV_METADATA_CONTENT_DISPOSABLE = "SCT_METADATA_CONTENT_DISPOSABLE";
/**
* This is the key of the header's key list needed to be transmitted. The list is a string split with ;.
* The value mapped by this key was specified by user.
* This is configured in environment variables.
*/
private static final String ENV_METADATA_CONTENT_RAW_TRANSHEADERS = "SCT_METADATA_CONTENT_RAW_TRANSHEADERS";
private static final String ENV_METADATA_ZONE = "SCT_METADATA_ZONE";
private static final String ENV_METADATA_REGION = "SCT_METADATA_REGION";
private static final String ENV_METADATA_CAMPUS = "SCT_METADATA_CAMPUS";
@ -100,7 +106,13 @@ public class StaticMetadataManager {
String value = entry.getValue();
if (StringUtils.isNotBlank(key) && key.startsWith(ENV_METADATA_PREFIX)
&& !key.equals(ENV_METADATA_CONTENT_TRANSITIVE)) {
String sourceKey = StringUtils.substring(key, ENV_METADATA_PREFIX_LENGTH);
String sourceKey = "";
if (key.equals(ENV_METADATA_CONTENT_RAW_TRANSHEADERS)) {
sourceKey = key;
}
else {
sourceKey = StringUtils.substring(key, ENV_METADATA_PREFIX_LENGTH);
}
envMetadata.put(sourceKey, value);
LOGGER.info("[SCT] resolve metadata from env. key = {}, value = {}", sourceKey, value);
@ -270,6 +282,10 @@ public class StaticMetadataManager {
return envMetadata;
}
public String getEnvTransHeaderMetadata() {
return envMetadata.get(ENV_METADATA_CONTENT_RAW_TRANSHEADERS);
}
public Map<String, String> getEnvTransitiveMetadata() {
return envTransitiveMetadata;
}

Loading…
Cancel
Save