diff --git a/sentinel-adapter/sentinel-api-gateway-adapter-common/src/main/java/com/alibaba/csp/sentinel/adapter/gateway/common/param/ConfigurableRequestItemParser.java b/sentinel-adapter/sentinel-api-gateway-adapter-common/src/main/java/com/alibaba/csp/sentinel/adapter/gateway/common/param/ConfigurableRequestItemParser.java
new file mode 100644
index 00000000..e4b7f80a
--- /dev/null
+++ b/sentinel-adapter/sentinel-api-gateway-adapter-common/src/main/java/com/alibaba/csp/sentinel/adapter/gateway/common/param/ConfigurableRequestItemParser.java
@@ -0,0 +1,161 @@
+/*
+ * Copyright 1999-2022 Alibaba Group Holding Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 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.alibaba.csp.sentinel.adapter.gateway.common.param;
+
+import com.alibaba.csp.sentinel.util.AssertUtil;
+import com.alibaba.csp.sentinel.util.StringUtil;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.function.BiFunction;
+import java.util.function.Function;
+
+/**
+ * delegate RequestItemParser, support add extractors to customize request item parse.
+ *
+ * example:
+ * if you want to get client real ip in multi nginx proxy, you can register SentinelGatewayFilter bean as follows
+ *
+ * ConfigurableRequestItemParser parser = new ConfigurableRequestItemParser<>(new ServerWebExchangeItemParser());
+ * List headerNames = Arrays.asList("X-Real-IP", "Client-IP");
+ * parser.addRemoteAddressExtractor(serverWebExchange -> {
+ * for (String headerKey : headerNames) {
+ * String remoteAddress = serverWebExchange.getRequest().getHeaders().getFirst(headerKey);
+ * if (StringUtils.hasLength(remoteAddress)) {
+ * return remoteAddress;
+ * }
+ * }
+ * return null;
+ * });
+ * return new SentinelGatewayFilter(parser);
+ *
+ * @author icodening
+ * @date 2022.01.14
+ */
+public class ConfigurableRequestItemParser implements RequestItemParser {
+
+ private final List> pathExtractors = new ArrayList<>(2);
+
+ private final List> remoteAddressExtractors = new ArrayList<>(2);
+
+ private final List> headerExtractors = new ArrayList<>(2);
+
+ private final List> urlParamExtractors = new ArrayList<>(2);
+
+ private final List> cookieValueExtractors = new ArrayList<>(2);
+
+ private final RequestItemParser delegate;
+
+ public ConfigurableRequestItemParser(RequestItemParser delegate) {
+ AssertUtil.notNull(delegate, "delegate can not be null");
+ this.delegate = delegate;
+ }
+
+ @Override
+ public String getPath(T request) {
+ for (Function extractor : pathExtractors) {
+ String pathValue = extractor.apply(request);
+ if (StringUtil.isNotBlank(pathValue)) {
+ return pathValue;
+ }
+ }
+ return delegate.getPath(request);
+ }
+
+ @Override
+ public String getRemoteAddress(T request) {
+ for (Function extractor : remoteAddressExtractors) {
+ String remoteAddress = extractor.apply(request);
+ if (StringUtil.isNotBlank(remoteAddress)) {
+ return remoteAddress;
+ }
+ }
+ return delegate.getRemoteAddress(request);
+ }
+
+ @Override
+ public String getHeader(T request, String key) {
+ for (BiFunction extractor : headerExtractors) {
+ String headerValue = extractor.apply(request, key);
+ if (StringUtil.isNotBlank(headerValue)) {
+ return headerValue;
+ }
+ }
+ return delegate.getHeader(request, key);
+ }
+
+ @Override
+ public String getUrlParam(T request, String paramName) {
+ for (BiFunction extractor : urlParamExtractors) {
+ String urlParam = extractor.apply(request, paramName);
+ if (StringUtil.isNotBlank(urlParam)) {
+ return urlParam;
+ }
+ }
+ return delegate.getUrlParam(request, paramName);
+ }
+
+ @Override
+ public String getCookieValue(T request, String cookieName) {
+ for (BiFunction extractor : cookieValueExtractors) {
+ String cookie = extractor.apply(request, cookieName);
+ if (StringUtil.isNotBlank(cookie)) {
+ return cookie;
+ }
+ }
+ return delegate.getCookieValue(request, cookieName);
+ }
+
+ public ConfigurableRequestItemParser addPathExtractor(Function extractor) {
+ if (extractor == null) {
+ return this;
+ }
+ pathExtractors.add(extractor);
+ return this;
+ }
+
+ public ConfigurableRequestItemParser addRemoteAddressExtractor(Function extractor) {
+ if (extractor == null) {
+ return this;
+ }
+ remoteAddressExtractors.add(extractor);
+ return this;
+ }
+
+ public ConfigurableRequestItemParser addHeaderExtractor(BiFunction extractor) {
+ if (extractor == null) {
+ return this;
+ }
+ headerExtractors.add(extractor);
+ return this;
+ }
+
+ public ConfigurableRequestItemParser addUrlParamExtractor(BiFunction extractor) {
+ if (extractor == null) {
+ return this;
+ }
+ urlParamExtractors.add(extractor);
+ return this;
+ }
+
+ public ConfigurableRequestItemParser addCookieValueExtractor(BiFunction extractor) {
+ if (extractor == null) {
+ return this;
+ }
+ cookieValueExtractors.add(extractor);
+ return this;
+ }
+}
diff --git a/sentinel-adapter/sentinel-spring-cloud-gateway-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/gateway/sc/SentinelGatewayFilter.java b/sentinel-adapter/sentinel-spring-cloud-gateway-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/gateway/sc/SentinelGatewayFilter.java
index 3dfbaa5a..a3552b6c 100644
--- a/sentinel-adapter/sentinel-spring-cloud-gateway-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/gateway/sc/SentinelGatewayFilter.java
+++ b/sentinel-adapter/sentinel-spring-cloud-gateway-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/gateway/sc/SentinelGatewayFilter.java
@@ -15,21 +15,18 @@
*/
package com.alibaba.csp.sentinel.adapter.gateway.sc;
-import java.util.Optional;
-import java.util.Set;
-import java.util.stream.Collectors;
-
import com.alibaba.csp.sentinel.EntryType;
import com.alibaba.csp.sentinel.ResourceTypeConstants;
import com.alibaba.csp.sentinel.adapter.gateway.common.SentinelGatewayConstants;
import com.alibaba.csp.sentinel.adapter.gateway.common.param.GatewayParamParser;
+import com.alibaba.csp.sentinel.adapter.gateway.common.param.RequestItemParser;
+import com.alibaba.csp.sentinel.adapter.gateway.sc.api.GatewayApiMatcherManager;
+import com.alibaba.csp.sentinel.adapter.gateway.sc.api.matcher.WebExchangeApiMatcher;
import com.alibaba.csp.sentinel.adapter.gateway.sc.callback.GatewayCallbackManager;
import com.alibaba.csp.sentinel.adapter.reactor.ContextConfig;
import com.alibaba.csp.sentinel.adapter.reactor.EntryConfig;
import com.alibaba.csp.sentinel.adapter.reactor.SentinelReactorTransformer;
-import com.alibaba.csp.sentinel.adapter.gateway.sc.api.GatewayApiMatcherManager;
-import com.alibaba.csp.sentinel.adapter.gateway.sc.api.matcher.WebExchangeApiMatcher;
-
+import com.alibaba.csp.sentinel.util.AssertUtil;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
@@ -39,6 +36,10 @@ import org.springframework.core.Ordered;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
+import java.util.Optional;
+import java.util.Set;
+import java.util.stream.Collectors;
+
/**
* @author Eric Zhao
* @since 1.6.0
@@ -47,16 +48,25 @@ public class SentinelGatewayFilter implements GatewayFilter, GlobalFilter, Order
private final int order;
+ private final GatewayParamParser paramParser;
+
public SentinelGatewayFilter() {
this(Ordered.HIGHEST_PRECEDENCE);
}
public SentinelGatewayFilter(int order) {
- this.order = order;
+ this(order, new ServerWebExchangeItemParser());
}
- private final GatewayParamParser paramParser = new GatewayParamParser<>(
- new ServerWebExchangeItemParser());
+ public SentinelGatewayFilter(RequestItemParser serverWebExchangeItemParser) {
+ this(Ordered.HIGHEST_PRECEDENCE, serverWebExchangeItemParser);
+ }
+
+ public SentinelGatewayFilter(int order, RequestItemParser requestItemParser) {
+ AssertUtil.notNull(requestItemParser, "requestItemParser cannot be null");
+ this.order = order;
+ this.paramParser = new GatewayParamParser<>(requestItemParser);
+ }
@Override
public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) {
diff --git a/sentinel-adapter/sentinel-zuul-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/gateway/zuul/filters/SentinelZuulPreFilter.java b/sentinel-adapter/sentinel-zuul-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/gateway/zuul/filters/SentinelZuulPreFilter.java
index 649ffa19..95e64328 100644
--- a/sentinel-adapter/sentinel-zuul-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/gateway/zuul/filters/SentinelZuulPreFilter.java
+++ b/sentinel-adapter/sentinel-zuul-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/gateway/zuul/filters/SentinelZuulPreFilter.java
@@ -26,6 +26,7 @@ import com.alibaba.csp.sentinel.EntryType;
import com.alibaba.csp.sentinel.ResourceTypeConstants;
import com.alibaba.csp.sentinel.SphU;
import com.alibaba.csp.sentinel.adapter.gateway.common.param.GatewayParamParser;
+import com.alibaba.csp.sentinel.adapter.gateway.common.param.RequestItemParser;
import com.alibaba.csp.sentinel.adapter.gateway.common.rule.GatewayFlowRule;
import com.alibaba.csp.sentinel.adapter.gateway.zuul.RequestContextItemParser;
import com.alibaba.csp.sentinel.adapter.gateway.zuul.api.ZuulGatewayApiMatcherManager;
@@ -37,6 +38,7 @@ import com.alibaba.csp.sentinel.adapter.gateway.zuul.fallback.ZuulBlockFallbackM
import com.alibaba.csp.sentinel.adapter.gateway.zuul.fallback.ZuulBlockFallbackProvider;
import com.alibaba.csp.sentinel.context.ContextUtil;
import com.alibaba.csp.sentinel.slots.block.BlockException;
+import com.alibaba.csp.sentinel.util.AssertUtil;
import com.alibaba.csp.sentinel.util.StringUtil;
import com.alibaba.csp.sentinel.util.function.Predicate;
@@ -59,15 +61,20 @@ public class SentinelZuulPreFilter extends ZuulFilter {
private final int order;
- private final GatewayParamParser paramParser = new GatewayParamParser<>(
- new RequestContextItemParser());
+ private final GatewayParamParser paramParser;
public SentinelZuulPreFilter() {
this(10000);
}
public SentinelZuulPreFilter(int order) {
+ this(order, new RequestContextItemParser());
+ }
+
+ public SentinelZuulPreFilter(int order, RequestItemParser requestItemParser) {
+ AssertUtil.notNull(requestItemParser, "requestItemParser cannot be null");
this.order = order;
+ this.paramParser = new GatewayParamParser<>(requestItemParser);
}
@Override
diff --git a/sentinel-adapter/sentinel-zuul2-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/gateway/zuul2/filters/inbound/SentinelZuulInboundFilter.java b/sentinel-adapter/sentinel-zuul2-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/gateway/zuul2/filters/inbound/SentinelZuulInboundFilter.java
index ff174538..344a2ca3 100644
--- a/sentinel-adapter/sentinel-zuul2-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/gateway/zuul2/filters/inbound/SentinelZuulInboundFilter.java
+++ b/sentinel-adapter/sentinel-zuul2-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/gateway/zuul2/filters/inbound/SentinelZuulInboundFilter.java
@@ -27,6 +27,7 @@ import com.alibaba.csp.sentinel.EntryType;
import com.alibaba.csp.sentinel.ResourceTypeConstants;
import com.alibaba.csp.sentinel.SphU;
import com.alibaba.csp.sentinel.adapter.gateway.common.param.GatewayParamParser;
+import com.alibaba.csp.sentinel.adapter.gateway.common.param.RequestItemParser;
import com.alibaba.csp.sentinel.adapter.gateway.zuul2.HttpRequestMessageItemParser;
import com.alibaba.csp.sentinel.adapter.gateway.zuul2.api.ZuulGatewayApiMatcherManager;
import com.alibaba.csp.sentinel.adapter.gateway.zuul2.api.matcher.HttpRequestMessageApiMatcher;
@@ -67,8 +68,7 @@ public class SentinelZuulInboundFilter extends HttpInboundFilter {
private final boolean fastError;
private final Function routeExtractor;
- private final GatewayParamParser paramParser = new GatewayParamParser<>(
- new HttpRequestMessageItemParser());
+ private final GatewayParamParser paramParser;
/**
* Constructor of the inbound filter, which extracts the route from the context route VIP attribute by default.
@@ -98,13 +98,20 @@ public class SentinelZuulInboundFilter extends HttpInboundFilter {
*/
public SentinelZuulInboundFilter(int order, String blockedEndpointName, Executor executor, boolean fastError,
Function routeExtractor) {
+ this(order, blockedEndpointName, executor, fastError, routeExtractor, new HttpRequestMessageItemParser());
+ }
+
+ public SentinelZuulInboundFilter(int order, String blockedEndpointName, Executor executor, boolean fastError,
+ Function routeExtractor, RequestItemParser requestItemParser) {
AssertUtil.notEmpty(blockedEndpointName, "blockedEndpointName cannot be empty");
AssertUtil.notNull(routeExtractor, "routeExtractor cannot be null");
+ AssertUtil.notNull(requestItemParser, "requestItemParser cannot be null");
this.order = order;
this.blockedEndpointName = blockedEndpointName;
this.executor = executor;
this.fastError = fastError;
this.routeExtractor = routeExtractor;
+ this.paramParser = new GatewayParamParser<>(requestItemParser);
}
@Override