From 1960c9c3797bf5f187e072b375faec665364b18e Mon Sep 17 00:00:00 2001 From: lepdou Date: Mon, 9 May 2022 19:01:40 +0800 Subject: [PATCH 1/4] optimize config server address --- CHANGELOG.md | 1 + .../polaris/config/ConfigurationModifier.java | 59 +++++++++++++++---- ...larisConfigBootstrapAutoConfiguration.java | 5 +- .../config/PolarisConfigProperties.java | 13 ++++ ...itional-spring-configuration-metadata.json | 7 +++ .../src/main/resources/bootstrap.yml | 2 +- 6 files changed, 74 insertions(+), 13 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 42918fbe6..c880e7b9f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,3 +9,4 @@ - [Feat: optimize router dependency](https://github.com/Tencent/spring-cloud-tencent/pull/114) - [Refactor: refactor transfer metadata](https://github.com/Tencent/spring-cloud-tencent/pull/112) - [feat:add switch of polaris, discovery and register.](https://github.com/Tencent/spring-cloud-tencent/pull/133) +- [feat:optimize config server address](https://github.com/Tencent/spring-cloud-tencent/pull/150) diff --git a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/ConfigurationModifier.java b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/ConfigurationModifier.java index 6c46f3c89..495d6ec3a 100644 --- a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/ConfigurationModifier.java +++ b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/ConfigurationModifier.java @@ -18,16 +18,19 @@ package com.tencent.cloud.polaris.config; +import java.util.ArrayList; import java.util.List; import com.tencent.cloud.common.constant.ContextConstant; import com.tencent.cloud.common.util.AddressUtils; import com.tencent.cloud.polaris.config.config.PolarisConfigProperties; import com.tencent.cloud.polaris.context.PolarisConfigModifier; +import com.tencent.cloud.polaris.context.PolarisContextProperties; import com.tencent.polaris.factory.config.ConfigurationImpl; +import org.apache.commons.lang.StringUtils; + +import org.springframework.util.CollectionUtils; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.util.StringUtils; /** * Read configuration from spring cloud's configuration file and override polaris.yaml. @@ -36,22 +39,38 @@ import org.springframework.util.StringUtils; */ public class ConfigurationModifier implements PolarisConfigModifier { - @Autowired - private PolarisConfigProperties polarisConfigProperties; + private final PolarisConfigProperties polarisConfigProperties; + + private final PolarisContextProperties polarisContextProperties; + + public ConfigurationModifier(PolarisConfigProperties polarisConfigProperties, + PolarisContextProperties polarisContextProperties) { + this.polarisConfigProperties = polarisConfigProperties; + this.polarisContextProperties = polarisContextProperties; + } @Override public void modify(ConfigurationImpl configuration) { + // set connector type configuration.getConfigFile().getServerConnector().setConnectorType("polaris"); - if (StringUtils.isEmpty(polarisConfigProperties.getAddress())) { - return; + // set config server address + List configAddresses; + String configAddressesStr = polarisConfigProperties.getAddress(); + + if (StringUtils.isNotEmpty(configAddressesStr)) { + configAddresses = AddressUtils.parseAddressList(polarisConfigProperties.getAddress()); + } + else { + configAddresses = resolveConfigAddressFromPolarisAddress(polarisContextProperties.getAddress()); } - // override polaris config server address - List addresses = AddressUtils - .parseAddressList(polarisConfigProperties.getAddress()); + if (CollectionUtils.isEmpty(configAddresses)) { + throw new RuntimeException("Config server address is blank. Please check your config in bootstrap.yml" + + " with spring.cloud.polaris.address or spring.cloud.polaris.config.address"); + } - configuration.getConfigFile().getServerConnector().setAddresses(addresses); + configuration.getConfigFile().getServerConnector().setAddresses(configAddresses); } @Override @@ -59,4 +78,24 @@ public class ConfigurationModifier implements PolarisConfigModifier { return ContextConstant.ModifierOrder.CONFIG_ORDER; } + /** + * In most cases, the address of the configuration center is the same as that of Polaris, but the port is different. + * Therefore, the address of the configuration center can be deduced directly from the Polaris address. + * + */ + private List resolveConfigAddressFromPolarisAddress(String polarisAddress) { + if (StringUtils.isEmpty(polarisAddress)) { + return null; + } + + List polarisAddresses = AddressUtils.parseAddressList(polarisAddress); + List configAddresses = new ArrayList<>(polarisAddresses.size()); + + for (String address : polarisAddresses) { + String ip = StringUtils.substringBeforeLast(address, ":"); + configAddresses.add(ip + ":" + polarisConfigProperties.getPort()); + } + + return configAddresses; + } } diff --git a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/PolarisConfigBootstrapAutoConfiguration.java b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/PolarisConfigBootstrapAutoConfiguration.java index 8c7044a8c..544ee78ac 100644 --- a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/PolarisConfigBootstrapAutoConfiguration.java +++ b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/PolarisConfigBootstrapAutoConfiguration.java @@ -70,8 +70,9 @@ public class PolarisConfigBootstrapAutoConfiguration { } @Bean - public ConfigurationModifier configurationModifier() { - return new ConfigurationModifier(); + public ConfigurationModifier configurationModifier(PolarisConfigProperties polarisConfigProperties, + PolarisContextProperties polarisContextProperties) { + return new ConfigurationModifier(polarisConfigProperties, polarisContextProperties); } } diff --git a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/config/PolarisConfigProperties.java b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/config/PolarisConfigProperties.java index 6ddc49f5f..a2c9032fe 100644 --- a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/config/PolarisConfigProperties.java +++ b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/config/PolarisConfigProperties.java @@ -39,6 +39,11 @@ public class PolarisConfigProperties { */ private String address; + /** + * Polaris config grpc port. + */ + private int port = 8093; + /** * Whether to automatically update to the spring context when the configuration file. * is updated @@ -66,6 +71,14 @@ public class PolarisConfigProperties { this.address = address; } + public int getPort() { + return port; + } + + public void setPort(int port) { + this.port = port; + } + public boolean isAutoRefresh() { return autoRefresh; } diff --git a/spring-cloud-starter-tencent-polaris-config/src/main/resources/META-INF/additional-spring-configuration-metadata.json b/spring-cloud-starter-tencent-polaris-config/src/main/resources/META-INF/additional-spring-configuration-metadata.json index 152d24d64..ee84cbd47 100644 --- a/spring-cloud-starter-tencent-polaris-config/src/main/resources/META-INF/additional-spring-configuration-metadata.json +++ b/spring-cloud-starter-tencent-polaris-config/src/main/resources/META-INF/additional-spring-configuration-metadata.json @@ -14,6 +14,13 @@ "description": "The polaris configuration server address.", "sourceType": "com.tencent.cloud.polaris.config.config.PolarisConfigProperties" }, + { + "name": "spring.cloud.polaris.config.port", + "type": "java.lang.Integer", + "defaultValue": "8093", + "description": "The polaris configuration server port.", + "sourceType": "com.tencent.cloud.polaris.config.config.PolarisConfigProperties" + }, { "name": "spring.cloud.polaris.config.auto-refresh", "type": "java.lang.Boolean", diff --git a/spring-cloud-tencent-examples/polaris-config-example/src/main/resources/bootstrap.yml b/spring-cloud-tencent-examples/polaris-config-example/src/main/resources/bootstrap.yml index b8ab4e08a..bdbd643f7 100644 --- a/spring-cloud-tencent-examples/polaris-config-example/src/main/resources/bootstrap.yml +++ b/spring-cloud-tencent-examples/polaris-config-example/src/main/resources/bootstrap.yml @@ -5,9 +5,9 @@ spring: name: polaris-config-example cloud: polaris: + address: grpc://127.0.0.1:8091 namespace: default config: - address: grpc://127.0.0.1:8093 auto-refresh: true # auto refresh when config file changed groups: - name: ${spring.application.name} # group name From b1d0ca6ee9f959d09b9c1b942ece023eb9b02f06 Mon Sep 17 00:00:00 2001 From: lepdou Date: Wed, 20 Apr 2022 19:52:17 +0800 Subject: [PATCH 2/4] remove maven format plugin --- CHANGELOG.md | 1 + pom.xml | 4 ---- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 42918fbe6..c06d0cfc4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,3 +9,4 @@ - [Feat: optimize router dependency](https://github.com/Tencent/spring-cloud-tencent/pull/114) - [Refactor: refactor transfer metadata](https://github.com/Tencent/spring-cloud-tencent/pull/112) - [feat:add switch of polaris, discovery and register.](https://github.com/Tencent/spring-cloud-tencent/pull/133) +- [Feature: Remove spring-javaformat-maven-plugin](https://github.com/Tencent/spring-cloud-tencent/pull/152) diff --git a/pom.xml b/pom.xml index 98cae4818..57667ae90 100644 --- a/pom.xml +++ b/pom.xml @@ -136,10 +136,6 @@ - - io.spring.javaformat - spring-javaformat-maven-plugin - org.apache.maven.plugins maven-checkstyle-plugin From 1b410e61d0a256037afa57c5e284fd7e246b7bd2 Mon Sep 17 00:00:00 2001 From: lepdou Date: Mon, 9 May 2022 19:55:25 +0800 Subject: [PATCH 3/4] Support custom rate limit reject response info (#154) Co-authored-by: Haotian Zhang <928016560@qq.com> --- CHANGELOG.md | 1 + .../config/PolarisRateLimitProperties.java | 71 +++++++++++++++++++ .../config/RateLimitConfiguration.java | 17 +++-- .../filter/QuotaCheckReactiveFilter.java | 23 ++++-- .../filter/QuotaCheckServletFilter.java | 21 ++++-- .../ratelimit/utils/RateLimitUtils.java | 70 ++++++++++++++++++ ...itional-spring-configuration-metadata.json | 18 +++++ .../cloud/common/util/ResourceFileUtils.java | 54 ++++++++++++++ .../ratelimit-callee-service/pom.xml | 47 +++++++----- .../src/main/resources/bootstrap.yml | 1 + .../src/main/resources/reject-tips.html | 5 ++ 11 files changed, 296 insertions(+), 32 deletions(-) create mode 100644 spring-cloud-starter-tencent-polaris-ratelimit/src/main/java/com/tencent/cloud/polaris/ratelimit/config/PolarisRateLimitProperties.java create mode 100644 spring-cloud-starter-tencent-polaris-ratelimit/src/main/java/com/tencent/cloud/polaris/ratelimit/utils/RateLimitUtils.java create mode 100644 spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/ResourceFileUtils.java create mode 100644 spring-cloud-tencent-examples/polaris-ratelimit-example/ratelimit-callee-service/src/main/resources/reject-tips.html diff --git a/CHANGELOG.md b/CHANGELOG.md index e2d842a70..3d19c23a4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,5 +9,6 @@ - [Feat: optimize router dependency](https://github.com/Tencent/spring-cloud-tencent/pull/114) - [Refactor: refactor transfer metadata](https://github.com/Tencent/spring-cloud-tencent/pull/112) - [feat:add switch of polaris, discovery and register.](https://github.com/Tencent/spring-cloud-tencent/pull/133) +- [Feature: Support custom rate limit reject response info](https://github.com/Tencent/spring-cloud-tencent/pull/154) - [Feature: Remove spring-javaformat-maven-plugin](https://github.com/Tencent/spring-cloud-tencent/pull/152) - [feat:optimize config server address](https://github.com/Tencent/spring-cloud-tencent/pull/150) diff --git a/spring-cloud-starter-tencent-polaris-ratelimit/src/main/java/com/tencent/cloud/polaris/ratelimit/config/PolarisRateLimitProperties.java b/spring-cloud-starter-tencent-polaris-ratelimit/src/main/java/com/tencent/cloud/polaris/ratelimit/config/PolarisRateLimitProperties.java new file mode 100644 index 000000000..d51d90b9c --- /dev/null +++ b/spring-cloud-starter-tencent-polaris-ratelimit/src/main/java/com/tencent/cloud/polaris/ratelimit/config/PolarisRateLimitProperties.java @@ -0,0 +1,71 @@ +/* + * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + */ + +package com.tencent.cloud.polaris.ratelimit.config; + +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.http.HttpStatus; + +/** + * The properties for rate limit. + * + * @author lepdou 2022-04-20 + */ +@ConfigurationProperties("spring.cloud.polaris.ratelimit") +public class PolarisRateLimitProperties { + + /** + * custom tips when reject request. + */ + private String rejectRequestTips; + + /** + * context file path. + */ + private String rejectRequestTipsFilePath; + + /** + * custom http code when reject request. + */ + private int rejectHttpCode = HttpStatus.TOO_MANY_REQUESTS.value(); + + public String getRejectRequestTips() { + return rejectRequestTips; + } + + public void setRejectRequestTips(String rejectRequestTips) { + this.rejectRequestTips = rejectRequestTips; + } + + public String getRejectRequestTipsFilePath() { + return rejectRequestTipsFilePath; + } + + public void setRejectRequestTipsFilePath(String rejectRequestTipsFilePath) { + this.rejectRequestTipsFilePath = rejectRequestTipsFilePath; + } + + public int getRejectHttpCode() { + return rejectHttpCode; + } + + public void setRejectHttpCode(int rejectHttpCode) { + this.rejectHttpCode = rejectHttpCode; + } + +} diff --git a/spring-cloud-starter-tencent-polaris-ratelimit/src/main/java/com/tencent/cloud/polaris/ratelimit/config/RateLimitConfiguration.java b/spring-cloud-starter-tencent-polaris-ratelimit/src/main/java/com/tencent/cloud/polaris/ratelimit/config/RateLimitConfiguration.java index f45b5cd0f..6eb5451ba 100644 --- a/spring-cloud-starter-tencent-polaris-ratelimit/src/main/java/com/tencent/cloud/polaris/ratelimit/config/RateLimitConfiguration.java +++ b/spring-cloud-starter-tencent-polaris-ratelimit/src/main/java/com/tencent/cloud/polaris/ratelimit/config/RateLimitConfiguration.java @@ -49,6 +49,11 @@ import static javax.servlet.DispatcherType.REQUEST; @ConditionalOnProperty(name = "spring.cloud.polaris.ratelimit.enabled", matchIfMissing = true) public class RateLimitConfiguration { + @Bean + public PolarisRateLimitProperties polarisRateLimitProperties() { + return new PolarisRateLimitProperties(); + } + @Bean @ConditionalOnMissingBean public LimitAPI limitAPI(SDKContext polarisContext) { @@ -65,8 +70,10 @@ public class RateLimitConfiguration { @Bean @ConditionalOnMissingBean public QuotaCheckServletFilter quotaCheckFilter(LimitAPI limitAPI, - @Nullable PolarisRateLimiterLabelServletResolver labelResolver) { - return new QuotaCheckServletFilter(limitAPI, labelResolver); + @Nullable PolarisRateLimiterLabelServletResolver labelResolver, + PolarisRateLimitProperties polarisRateLimitProperties) { + return new QuotaCheckServletFilter(limitAPI, labelResolver, + polarisRateLimitProperties); } @Bean @@ -91,8 +98,10 @@ public class RateLimitConfiguration { @Bean public QuotaCheckReactiveFilter quotaCheckReactiveFilter(LimitAPI limitAPI, - @Nullable PolarisRateLimiterLabelReactiveResolver labelResolver) { - return new QuotaCheckReactiveFilter(limitAPI, labelResolver); + @Nullable PolarisRateLimiterLabelReactiveResolver labelResolver, + PolarisRateLimitProperties polarisRateLimitProperties) { + return new QuotaCheckReactiveFilter(limitAPI, labelResolver, + polarisRateLimitProperties); } } diff --git a/spring-cloud-starter-tencent-polaris-ratelimit/src/main/java/com/tencent/cloud/polaris/ratelimit/filter/QuotaCheckReactiveFilter.java b/spring-cloud-starter-tencent-polaris-ratelimit/src/main/java/com/tencent/cloud/polaris/ratelimit/filter/QuotaCheckReactiveFilter.java index 0db616f7f..9a0db9a77 100644 --- a/spring-cloud-starter-tencent-polaris-ratelimit/src/main/java/com/tencent/cloud/polaris/ratelimit/filter/QuotaCheckReactiveFilter.java +++ b/spring-cloud-starter-tencent-polaris-ratelimit/src/main/java/com/tencent/cloud/polaris/ratelimit/filter/QuotaCheckReactiveFilter.java @@ -22,10 +22,14 @@ import java.nio.charset.StandardCharsets; import java.util.HashMap; import java.util.Map; +import javax.annotation.PostConstruct; + import com.tencent.cloud.common.metadata.MetadataContext; +import com.tencent.cloud.polaris.ratelimit.config.PolarisRateLimitProperties; import com.tencent.cloud.polaris.ratelimit.constant.RateLimitConstant; import com.tencent.cloud.polaris.ratelimit.spi.PolarisRateLimiterLabelReactiveResolver; import com.tencent.cloud.polaris.ratelimit.utils.QuotaCheckUtils; +import com.tencent.cloud.polaris.ratelimit.utils.RateLimitUtils; import com.tencent.polaris.ratelimit.api.core.LimitAPI; import com.tencent.polaris.ratelimit.api.rpc.QuotaResponse; import com.tencent.polaris.ratelimit.api.rpc.QuotaResultCode; @@ -36,7 +40,6 @@ import reactor.core.publisher.Mono; import org.springframework.core.Ordered; import org.springframework.core.io.buffer.DataBuffer; -import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.http.server.reactive.ServerHttpResponse; import org.springframework.util.CollectionUtils; @@ -60,10 +63,21 @@ public class QuotaCheckReactiveFilter implements WebFilter, Ordered { private final PolarisRateLimiterLabelReactiveResolver labelResolver; + private final PolarisRateLimitProperties polarisRateLimitProperties; + + private String rejectTips; + public QuotaCheckReactiveFilter(LimitAPI limitAPI, - PolarisRateLimiterLabelReactiveResolver labelResolver) { + PolarisRateLimiterLabelReactiveResolver labelResolver, + PolarisRateLimitProperties polarisRateLimitProperties) { this.limitAPI = limitAPI; this.labelResolver = labelResolver; + this.polarisRateLimitProperties = polarisRateLimitProperties; + } + + @PostConstruct + public void init() { + rejectTips = RateLimitUtils.getRejectTips(polarisRateLimitProperties); } @Override @@ -104,11 +118,10 @@ public class QuotaCheckReactiveFilter implements WebFilter, Ordered { if (quotaResponse.getCode() == QuotaResultCode.QuotaResultLimited) { ServerHttpResponse response = exchange.getResponse(); - response.setStatusCode(HttpStatus.TOO_MANY_REQUESTS); + response.setRawStatusCode(polarisRateLimitProperties.getRejectHttpCode()); response.getHeaders().setContentType(MediaType.APPLICATION_JSON); DataBuffer dataBuffer = response.bufferFactory().allocateBuffer() - .write(RateLimitConstant.QUOTA_LIMITED_INFO - .getBytes(StandardCharsets.UTF_8)); + .write(rejectTips.getBytes(StandardCharsets.UTF_8)); return response.writeWith(Mono.just(dataBuffer)); } } diff --git a/spring-cloud-starter-tencent-polaris-ratelimit/src/main/java/com/tencent/cloud/polaris/ratelimit/filter/QuotaCheckServletFilter.java b/spring-cloud-starter-tencent-polaris-ratelimit/src/main/java/com/tencent/cloud/polaris/ratelimit/filter/QuotaCheckServletFilter.java index 85706d944..ae1601093 100644 --- a/spring-cloud-starter-tencent-polaris-ratelimit/src/main/java/com/tencent/cloud/polaris/ratelimit/filter/QuotaCheckServletFilter.java +++ b/spring-cloud-starter-tencent-polaris-ratelimit/src/main/java/com/tencent/cloud/polaris/ratelimit/filter/QuotaCheckServletFilter.java @@ -22,15 +22,18 @@ import java.io.IOException; import java.util.HashMap; import java.util.Map; +import javax.annotation.PostConstruct; import javax.servlet.FilterChain; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import com.tencent.cloud.common.metadata.MetadataContext; +import com.tencent.cloud.polaris.ratelimit.config.PolarisRateLimitProperties; import com.tencent.cloud.polaris.ratelimit.constant.RateLimitConstant; import com.tencent.cloud.polaris.ratelimit.spi.PolarisRateLimiterLabelServletResolver; import com.tencent.cloud.polaris.ratelimit.utils.QuotaCheckUtils; +import com.tencent.cloud.polaris.ratelimit.utils.RateLimitUtils; import com.tencent.polaris.ratelimit.api.core.LimitAPI; import com.tencent.polaris.ratelimit.api.rpc.QuotaResponse; import com.tencent.polaris.ratelimit.api.rpc.QuotaResultCode; @@ -43,7 +46,6 @@ import org.springframework.util.CollectionUtils; import org.springframework.web.filter.OncePerRequestFilter; import static com.tencent.cloud.polaris.ratelimit.constant.RateLimitConstant.LABEL_METHOD; -import static org.springframework.http.HttpStatus.TOO_MANY_REQUESTS; /** * Servlet filter to check quota. @@ -60,10 +62,21 @@ public class QuotaCheckServletFilter extends OncePerRequestFilter { private final PolarisRateLimiterLabelServletResolver labelResolver; + private final PolarisRateLimitProperties polarisRateLimitProperties; + + private String rejectTips; + public QuotaCheckServletFilter(LimitAPI limitAPI, - PolarisRateLimiterLabelServletResolver labelResolver) { + PolarisRateLimiterLabelServletResolver labelResolver, + PolarisRateLimitProperties polarisRateLimitProperties) { this.limitAPI = limitAPI; this.labelResolver = labelResolver; + this.polarisRateLimitProperties = polarisRateLimitProperties; + } + + @PostConstruct + public void init() { + rejectTips = RateLimitUtils.getRejectTips(polarisRateLimitProperties); } @Override @@ -100,8 +113,8 @@ public class QuotaCheckServletFilter extends OncePerRequestFilter { QuotaResponse quotaResponse = QuotaCheckUtils.getQuota(limitAPI, localNamespace, localService, 1, labels, null); if (quotaResponse.getCode() == QuotaResultCode.QuotaResultLimited) { - response.setStatus(TOO_MANY_REQUESTS.value()); - response.getWriter().write(RateLimitConstant.QUOTA_LIMITED_INFO); + response.setStatus(polarisRateLimitProperties.getRejectHttpCode()); + response.getWriter().write(rejectTips); } else { filterChain.doFilter(request, response); diff --git a/spring-cloud-starter-tencent-polaris-ratelimit/src/main/java/com/tencent/cloud/polaris/ratelimit/utils/RateLimitUtils.java b/spring-cloud-starter-tencent-polaris-ratelimit/src/main/java/com/tencent/cloud/polaris/ratelimit/utils/RateLimitUtils.java new file mode 100644 index 000000000..2e036909c --- /dev/null +++ b/spring-cloud-starter-tencent-polaris-ratelimit/src/main/java/com/tencent/cloud/polaris/ratelimit/utils/RateLimitUtils.java @@ -0,0 +1,70 @@ +/* + * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + */ + +package com.tencent.cloud.polaris.ratelimit.utils; + +import com.tencent.cloud.common.util.ResourceFileUtils; +import com.tencent.cloud.polaris.ratelimit.config.PolarisRateLimitProperties; +import com.tencent.cloud.polaris.ratelimit.constant.RateLimitConstant; +import com.tencent.cloud.polaris.ratelimit.filter.QuotaCheckServletFilter; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import org.springframework.util.StringUtils; + +/** + * Rate limit utils. + * + * @author lepdou 2022-04-20 + */ +public final class RateLimitUtils { + + private static final Logger LOG = LoggerFactory + .getLogger(QuotaCheckServletFilter.class); + + private RateLimitUtils() { + + } + + public static String getRejectTips( + PolarisRateLimitProperties polarisRateLimitProperties) { + String tips = polarisRateLimitProperties.getRejectRequestTips(); + + if (!StringUtils.isEmpty(tips)) { + return tips; + } + + String rejectFilePath = polarisRateLimitProperties.getRejectRequestTipsFilePath(); + if (!StringUtils.isEmpty(rejectFilePath)) { + try { + tips = ResourceFileUtils.readFile(rejectFilePath); + } + catch (Exception e) { + LOG.error("[RateLimit] Read custom reject tips file error. path = {}", + rejectFilePath, e); + } + } + + if (!StringUtils.isEmpty(tips)) { + return tips; + } + + return RateLimitConstant.QUOTA_LIMITED_INFO; + } + +} diff --git a/spring-cloud-starter-tencent-polaris-ratelimit/src/main/resources/META-INF/additional-spring-configuration-metadata.json b/spring-cloud-starter-tencent-polaris-ratelimit/src/main/resources/META-INF/additional-spring-configuration-metadata.json index b71a17cc4..19b37aeb5 100644 --- a/spring-cloud-starter-tencent-polaris-ratelimit/src/main/resources/META-INF/additional-spring-configuration-metadata.json +++ b/spring-cloud-starter-tencent-polaris-ratelimit/src/main/resources/META-INF/additional-spring-configuration-metadata.json @@ -5,6 +5,24 @@ "type": "java.lang.Boolean", "defaultValue": true, "description": "Enable polaris rate limit or not." + }, + { + "name": "spring.cloud.polaris.ratelimit.rejectRequestTips", + "type": "java.lang.String", + "defaultValue": "", + "description": "Custom tips when reject request." + }, + { + "name": "spring.cloud.polaris.ratelimit.rejectRequestTipsFilePath", + "type": "java.lang.String", + "defaultValue": "", + "description": "Custom tips file path when reject request." + }, + { + "name": "spring.cloud.polaris.ratelimit.rejectHttpCode", + "type": "java.lang.Integer", + "defaultValue": "429", + "description": "Custom http code when reject request." } ] } diff --git a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/ResourceFileUtils.java b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/ResourceFileUtils.java new file mode 100644 index 000000000..d79bfce8b --- /dev/null +++ b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/ResourceFileUtils.java @@ -0,0 +1,54 @@ +/* + * 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.IOException; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; + +import org.springframework.core.io.ClassPathResource; + +/** + * Read file content from classpath resource. + * + * @author lepdou 2022-04-20 + */ +public final class ResourceFileUtils { + + private ResourceFileUtils() { + } + + public static String readFile(String path) throws IOException { + StringBuilder sb = new StringBuilder(); + + ClassPathResource classPathResource = new ClassPathResource(path); + + if (classPathResource.exists() && classPathResource.isReadable()) { + try (InputStream inputStream = classPathResource.getInputStream()) { + byte[] buffer = new byte[1024 * 10]; + int len; + while ((len = inputStream.read(buffer)) != -1) { + sb.append(new String(buffer, 0, len, StandardCharsets.UTF_8)); + } + } + } + return sb.toString(); + } + +} diff --git a/spring-cloud-tencent-examples/polaris-ratelimit-example/ratelimit-callee-service/pom.xml b/spring-cloud-tencent-examples/polaris-ratelimit-example/ratelimit-callee-service/pom.xml index 62af83910..dd28040b5 100644 --- a/spring-cloud-tencent-examples/polaris-ratelimit-example/ratelimit-callee-service/pom.xml +++ b/spring-cloud-tencent-examples/polaris-ratelimit-example/ratelimit-callee-service/pom.xml @@ -1,27 +1,36 @@ - - polaris-ratelimit-example - com.tencent.cloud - ${revision} - ../pom.xml - - 4.0.0 + xmlns="http://maven.apache.org/POM/4.0.0" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + + polaris-ratelimit-example + com.tencent.cloud + ${revision} + ../pom.xml + + 4.0.0 - ratelimit-callee-service + ratelimit-callee-service - - - org.springframework.boot - spring-boot-starter-web - + + + org.springframework.boot + spring-boot-starter-web + - com.tencent.cloud - spring-cloud-starter-tencent-polaris-ratelimit - + com.tencent.cloud + spring-cloud-starter-tencent-polaris-ratelimit + + + - + + + + org.springframework.boot + spring-boot-maven-plugin + + + diff --git a/spring-cloud-tencent-examples/polaris-ratelimit-example/ratelimit-callee-service/src/main/resources/bootstrap.yml b/spring-cloud-tencent-examples/polaris-ratelimit-example/ratelimit-callee-service/src/main/resources/bootstrap.yml index 8825b0cea..a33fc48f1 100644 --- a/spring-cloud-tencent-examples/polaris-ratelimit-example/ratelimit-callee-service/src/main/resources/bootstrap.yml +++ b/spring-cloud-tencent-examples/polaris-ratelimit-example/ratelimit-callee-service/src/main/resources/bootstrap.yml @@ -10,3 +10,4 @@ spring: enabled: true ratelimit: enabled: true + rejectRequestTipsFilePath: reject-tips.html diff --git a/spring-cloud-tencent-examples/polaris-ratelimit-example/ratelimit-callee-service/src/main/resources/reject-tips.html b/spring-cloud-tencent-examples/polaris-ratelimit-example/ratelimit-callee-service/src/main/resources/reject-tips.html new file mode 100644 index 000000000..693ef256b --- /dev/null +++ b/spring-cloud-tencent-examples/polaris-ratelimit-example/ratelimit-callee-service/src/main/resources/reject-tips.html @@ -0,0 +1,5 @@ +

+ + Custom reject content. + +

From 0cfec407a084b430d88b6086795de91049c2a42f Mon Sep 17 00:00:00 2001 From: lepdou Date: Tue, 10 May 2022 19:16:16 +0800 Subject: [PATCH 4/4] fix custom ratelimit reject httpcode --- .../ratelimit/filter/QuotaCheckReactiveFilter.java | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/spring-cloud-starter-tencent-polaris-ratelimit/src/main/java/com/tencent/cloud/polaris/ratelimit/filter/QuotaCheckReactiveFilter.java b/spring-cloud-starter-tencent-polaris-ratelimit/src/main/java/com/tencent/cloud/polaris/ratelimit/filter/QuotaCheckReactiveFilter.java index 9a0db9a77..fc0a1e9f3 100644 --- a/spring-cloud-starter-tencent-polaris-ratelimit/src/main/java/com/tencent/cloud/polaris/ratelimit/filter/QuotaCheckReactiveFilter.java +++ b/spring-cloud-starter-tencent-polaris-ratelimit/src/main/java/com/tencent/cloud/polaris/ratelimit/filter/QuotaCheckReactiveFilter.java @@ -40,6 +40,7 @@ import reactor.core.publisher.Mono; import org.springframework.core.Ordered; import org.springframework.core.io.buffer.DataBuffer; +import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.http.server.reactive.ServerHttpResponse; import org.springframework.util.CollectionUtils; @@ -118,7 +119,15 @@ public class QuotaCheckReactiveFilter implements WebFilter, Ordered { if (quotaResponse.getCode() == QuotaResultCode.QuotaResultLimited) { ServerHttpResponse response = exchange.getResponse(); - response.setRawStatusCode(polarisRateLimitProperties.getRejectHttpCode()); + HttpStatus httpStatus; + try { + httpStatus = HttpStatus.valueOf(polarisRateLimitProperties.getRejectHttpCode()); + } + catch (IllegalArgumentException e) { + LOG.error("Illegal custom reject http code, will fallback to default http code 429 [TOO_MANY_REQUESTS]"); + httpStatus = HttpStatus.TOO_MANY_REQUESTS; + } + response.setStatusCode(httpStatus); response.getHeaders().setContentType(MediaType.APPLICATION_JSON); DataBuffer dataBuffer = response.bufferFactory().allocateBuffer() .write(rejectTips.getBytes(StandardCharsets.UTF_8));