From bcb9b8be1106ae6c9b86051380229c446401c461 Mon Sep 17 00:00:00 2001
From: uuuyuqi
Date: Tue, 28 Apr 2026 11:41:15 +0800
Subject: [PATCH 1/5] feat: add Apache HttpClient 5.x adapter for Sentinel
Add sentinel-apache-httpclient5-adapter module that integrates Sentinel
flow control with Apache HttpClient 5.x outgoing HTTP requests.
Features:
- ExecChainHandler-based integration (SentinelApacheHttpClient5Handler)
- Configurable resource name extraction (METHOD:URL format by default)
- Query string and fragment stripping in resource names
- Customizable fallback handling (throws SentinelRpcException by default)
- Configurable resource name prefix (default: "httpclient:")
Follows the same architecture pattern as the existing HttpClient 4.x
adapter while adapting to HC5's ExecChainHandler API.
Closes #3614
Change-Id: I966295da9419beac99451fc6c9c31b1d75a9e7e6
Co-developed-by: Cursor
---
sentinel-adapter/pom.xml | 1 +
.../README.md | 77 ++++++++
.../pom.xml | 72 ++++++++
.../SentinelApacheHttpClient5Handler.java | 92 ++++++++++
.../SentinelApacheHttpClientConfig.java | 59 ++++++
.../ApacheHttpClientResourceExtractor.java | 34 ++++
...aultApacheHttpClientResourceExtractor.java | 55 ++++++
.../fallback/ApacheHttpClientFallback.java | 37 ++++
.../DefaultApacheHttpClientFallback.java | 32 ++++
.../SentinelApacheHttpClientTest.java | 168 ++++++++++++++++++
.../httpclient5/app/TestApplication.java | 30 ++++
.../app/controller/TestController.java | 52 ++++++
.../SentinelApacheHttpClientConfigTest.java | 70 ++++++++
...ApacheHttpClientResourceExtractorTest.java | 85 +++++++++
.../ApacheHttpClientFallbackTest.java | 34 ++++
15 files changed, 898 insertions(+)
create mode 100644 sentinel-adapter/sentinel-apache-httpclient5-adapter/README.md
create mode 100644 sentinel-adapter/sentinel-apache-httpclient5-adapter/pom.xml
create mode 100644 sentinel-adapter/sentinel-apache-httpclient5-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/apache/httpclient5/SentinelApacheHttpClient5Handler.java
create mode 100644 sentinel-adapter/sentinel-apache-httpclient5-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/apache/httpclient5/config/SentinelApacheHttpClientConfig.java
create mode 100644 sentinel-adapter/sentinel-apache-httpclient5-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/apache/httpclient5/extractor/ApacheHttpClientResourceExtractor.java
create mode 100644 sentinel-adapter/sentinel-apache-httpclient5-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/apache/httpclient5/extractor/DefaultApacheHttpClientResourceExtractor.java
create mode 100644 sentinel-adapter/sentinel-apache-httpclient5-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/apache/httpclient5/fallback/ApacheHttpClientFallback.java
create mode 100644 sentinel-adapter/sentinel-apache-httpclient5-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/apache/httpclient5/fallback/DefaultApacheHttpClientFallback.java
create mode 100644 sentinel-adapter/sentinel-apache-httpclient5-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/apache/httpclient5/SentinelApacheHttpClientTest.java
create mode 100644 sentinel-adapter/sentinel-apache-httpclient5-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/apache/httpclient5/app/TestApplication.java
create mode 100644 sentinel-adapter/sentinel-apache-httpclient5-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/apache/httpclient5/app/controller/TestController.java
create mode 100644 sentinel-adapter/sentinel-apache-httpclient5-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/apache/httpclient5/config/SentinelApacheHttpClientConfigTest.java
create mode 100644 sentinel-adapter/sentinel-apache-httpclient5-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/apache/httpclient5/extractor/DefaultApacheHttpClientResourceExtractorTest.java
create mode 100644 sentinel-adapter/sentinel-apache-httpclient5-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/apache/httpclient5/fallback/ApacheHttpClientFallbackTest.java
diff --git a/sentinel-adapter/pom.xml b/sentinel-adapter/pom.xml
index b075b54f0f..b1b87ac0a9 100755
--- a/sentinel-adapter/pom.xml
+++ b/sentinel-adapter/pom.xml
@@ -21,6 +21,7 @@
sentinel-apache-dubbo-adapter
sentinel-apache-dubbo3-adapter
sentinel-apache-httpclient-adapter
+ sentinel-apache-httpclient5-adapter
sentinel-sofa-rpc-adapter
sentinel-grpc-adapter
sentinel-zuul-adapter
diff --git a/sentinel-adapter/sentinel-apache-httpclient5-adapter/README.md b/sentinel-adapter/sentinel-apache-httpclient5-adapter/README.md
new file mode 100644
index 0000000000..e7770c2779
--- /dev/null
+++ b/sentinel-adapter/sentinel-apache-httpclient5-adapter/README.md
@@ -0,0 +1,77 @@
+# Sentinel Apache HttpClient 5.x Adapter
+
+## Introduction
+
+Sentinel provides integration for Apache HttpClient 5.x to enable flow control for outgoing HTTP requests.
+
+## Usage
+
+### Add dependency
+
+```xml
+
+ com.alibaba.csp
+ sentinel-apache-httpclient5-adapter
+ x.y.z
+
+```
+
+### Build the HttpClient
+
+```java
+CloseableHttpClient httpclient = HttpClients.custom()
+ .addExecInterceptorBefore(ChainElement.MAIN_TRANSPORT.name(), "sentinel",
+ new SentinelApacheHttpClient5Handler())
+ .build();
+```
+
+Or with custom configuration:
+
+```java
+SentinelApacheHttpClientConfig config = new SentinelApacheHttpClientConfig();
+config.setPrefix("httpclient:");
+config.setExtractor(myExtractor);
+config.setFallback(myFallback);
+
+CloseableHttpClient httpclient = HttpClients.custom()
+ .addExecInterceptorBefore(ChainElement.MAIN_TRANSPORT.name(), "sentinel",
+ new SentinelApacheHttpClient5Handler(config))
+ .build();
+```
+
+### Configuration
+
+| Name | Description | Type | Default Value |
+|------|------------|------|---------------|
+| prefix | Customize resource prefix | `String` | `httpclient:` |
+| extractor | Customize resource extractor | `ApacheHttpClientResourceExtractor` | `DefaultApacheHttpClientResourceExtractor` |
+| fallback | Handle request when it is blocked | `ApacheHttpClientFallback` | `DefaultApacheHttpClientFallback` |
+
+### Resource Extractor
+
+The default extractor generates resource names in the format `METHOD:url` (e.g. `GET:http://example.com/api/users`),
+with query parameters and fragments stripped. You can customize this by implementing `ApacheHttpClientResourceExtractor`:
+
+```java
+public class MyResourceExtractor implements ApacheHttpClientResourceExtractor {
+ @Override
+ public String extractor(ClassicHttpRequest request) {
+ // custom resource name extraction logic
+ return request.getMethod() + ":" + request.getRequestUri();
+ }
+}
+```
+
+### Fallback
+
+The default fallback throws `SentinelRpcException`. You can customize the behavior:
+
+```java
+public class MyFallback implements ApacheHttpClientFallback {
+ @Override
+ public ClassicHttpResponse handle(ClassicHttpRequest request, BlockException e) {
+ // return a custom response or throw exception
+ throw new SentinelRpcException(e);
+ }
+}
+```
diff --git a/sentinel-adapter/sentinel-apache-httpclient5-adapter/pom.xml b/sentinel-adapter/sentinel-apache-httpclient5-adapter/pom.xml
new file mode 100644
index 0000000000..f7a44438e4
--- /dev/null
+++ b/sentinel-adapter/sentinel-apache-httpclient5-adapter/pom.xml
@@ -0,0 +1,72 @@
+
+
+
+ com.alibaba.csp
+ sentinel-adapter
+ ${revision}
+ ../pom.xml
+
+ 4.0.0
+
+ ${project.groupId}:${project.artifactId}
+
+ sentinel-apache-httpclient5-adapter
+ jar
+
+
+ 5.1
+ 2.1.3.RELEASE
+ 5.1.5.RELEASE
+
+
+
+
+ com.alibaba.csp
+ sentinel-core
+
+
+ org.apache.httpcomponents.client5
+ httpclient5
+ ${apache.httpclient5.version}
+ provided
+
+
+
+ junit
+ junit
+ test
+
+
+
+ org.mockito
+ mockito-core
+ test
+
+
+ com.alibaba
+ fastjson
+ test
+
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+ ${spring.boot.version}
+ test
+
+
+ org.springframework.boot
+ spring-boot-test
+ ${spring.boot.version}
+ test
+
+
+ org.springframework
+ spring-test
+ ${spring-test.version}
+ test
+
+
+
diff --git a/sentinel-adapter/sentinel-apache-httpclient5-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/apache/httpclient5/SentinelApacheHttpClient5Handler.java b/sentinel-adapter/sentinel-apache-httpclient5-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/apache/httpclient5/SentinelApacheHttpClient5Handler.java
new file mode 100644
index 0000000000..2de5aa2f77
--- /dev/null
+++ b/sentinel-adapter/sentinel-apache-httpclient5-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/apache/httpclient5/SentinelApacheHttpClient5Handler.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright 1999-2020 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
+ *
+ * http://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.apache.httpclient5;
+
+import com.alibaba.csp.sentinel.Entry;
+import com.alibaba.csp.sentinel.EntryType;
+import com.alibaba.csp.sentinel.ResourceTypeConstants;
+import com.alibaba.csp.sentinel.SphU;
+import com.alibaba.csp.sentinel.Tracer;
+import com.alibaba.csp.sentinel.adapter.apache.httpclient5.config.SentinelApacheHttpClientConfig;
+import com.alibaba.csp.sentinel.slots.block.BlockException;
+import com.alibaba.csp.sentinel.util.StringUtil;
+import org.apache.hc.client5.http.classic.ExecChain;
+import org.apache.hc.client5.http.classic.ExecChainHandler;
+import org.apache.hc.core5.http.ClassicHttpRequest;
+import org.apache.hc.core5.http.ClassicHttpResponse;
+import org.apache.hc.core5.http.HttpException;
+
+import java.io.IOException;
+
+/**
+ * Apache HttpClient 5.x adapter for Sentinel.
+ *
+ * This handler implements {@link ExecChainHandler} to intercept outgoing HTTP requests
+ * and protect them with Sentinel flow control.
+ *
+ * Usage example:
+ * {@code
+ * CloseableHttpClient httpclient = HttpClients.custom()
+ * .addExecInterceptorBefore(ChainElement.MAIN_TRANSPORT.name(), "sentinel",
+ * new SentinelApacheHttpClient5Handler())
+ * .build();
+ * }
+ *
+ * @author qihuai.wyq
+ */
+public class SentinelApacheHttpClient5Handler implements ExecChainHandler {
+
+ private final SentinelApacheHttpClientConfig config;
+
+ public SentinelApacheHttpClient5Handler() {
+ this.config = new SentinelApacheHttpClientConfig();
+ }
+
+ public SentinelApacheHttpClient5Handler(SentinelApacheHttpClientConfig config) {
+ this.config = config;
+ }
+
+ @Override
+ public ClassicHttpResponse execute(ClassicHttpRequest classicHttpRequest, ExecChain.Scope scope,
+ ExecChain execChain) throws IOException, HttpException {
+ String name = config.getExtractor().extractor(classicHttpRequest);
+ if (StringUtil.isEmpty(name)) {
+ return execChain.proceed(classicHttpRequest, scope);
+ }
+
+ if (StringUtil.isNotEmpty(config.getPrefix())) {
+ name = config.getPrefix() + name;
+ }
+
+ Entry entry = null;
+ try {
+ entry = SphU.entry(name, ResourceTypeConstants.COMMON_WEB, EntryType.OUT);
+ return execChain.proceed(classicHttpRequest, scope);
+ } catch (BlockException e) {
+ return config.getFallback().handle(classicHttpRequest, e);
+ } catch (IOException | HttpException | RuntimeException e) {
+ Tracer.traceEntry(e, entry);
+ throw e;
+ } catch (Throwable t) {
+ Tracer.traceEntry(t, entry);
+ throw new RuntimeException(t);
+ } finally {
+ if (entry != null) {
+ entry.exit();
+ }
+ }
+ }
+}
diff --git a/sentinel-adapter/sentinel-apache-httpclient5-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/apache/httpclient5/config/SentinelApacheHttpClientConfig.java b/sentinel-adapter/sentinel-apache-httpclient5-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/apache/httpclient5/config/SentinelApacheHttpClientConfig.java
new file mode 100644
index 0000000000..b52f49a056
--- /dev/null
+++ b/sentinel-adapter/sentinel-apache-httpclient5-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/apache/httpclient5/config/SentinelApacheHttpClientConfig.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright 1999-2020 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
+ *
+ * http://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.apache.httpclient5.config;
+
+import com.alibaba.csp.sentinel.adapter.apache.httpclient5.extractor.ApacheHttpClientResourceExtractor;
+import com.alibaba.csp.sentinel.adapter.apache.httpclient5.extractor.DefaultApacheHttpClientResourceExtractor;
+import com.alibaba.csp.sentinel.adapter.apache.httpclient5.fallback.ApacheHttpClientFallback;
+import com.alibaba.csp.sentinel.adapter.apache.httpclient5.fallback.DefaultApacheHttpClientFallback;
+import com.alibaba.csp.sentinel.util.AssertUtil;
+
+/**
+ * @author qihuai.wyq
+ */
+public class SentinelApacheHttpClientConfig {
+
+ private String prefix = "httpclient:";
+ private ApacheHttpClientResourceExtractor extractor = new DefaultApacheHttpClientResourceExtractor();
+ private ApacheHttpClientFallback fallback = new DefaultApacheHttpClientFallback();
+
+ public String getPrefix() {
+ return prefix;
+ }
+
+ public void setPrefix(String prefix) {
+ AssertUtil.notNull(prefix, "prefix cannot be null");
+ this.prefix = prefix;
+ }
+
+ public ApacheHttpClientResourceExtractor getExtractor() {
+ return extractor;
+ }
+
+ public void setExtractor(ApacheHttpClientResourceExtractor extractor) {
+ AssertUtil.notNull(extractor, "extractor cannot be null");
+ this.extractor = extractor;
+ }
+
+ public ApacheHttpClientFallback getFallback() {
+ return fallback;
+ }
+
+ public void setFallback(ApacheHttpClientFallback fallback) {
+ AssertUtil.notNull(fallback, "fallback cannot be null");
+ this.fallback = fallback;
+ }
+}
diff --git a/sentinel-adapter/sentinel-apache-httpclient5-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/apache/httpclient5/extractor/ApacheHttpClientResourceExtractor.java b/sentinel-adapter/sentinel-apache-httpclient5-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/apache/httpclient5/extractor/ApacheHttpClientResourceExtractor.java
new file mode 100644
index 0000000000..94ab406022
--- /dev/null
+++ b/sentinel-adapter/sentinel-apache-httpclient5-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/apache/httpclient5/extractor/ApacheHttpClientResourceExtractor.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright 1999-2020 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
+ *
+ * http://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.apache.httpclient5.extractor;
+
+import org.apache.hc.core5.http.ClassicHttpRequest;
+
+/**
+ * Extracts Sentinel resource name from an Apache HttpClient 5.x request.
+ *
+ * @author qihuai.wyq
+ */
+public interface ApacheHttpClientResourceExtractor {
+
+ /**
+ * Extract resource name from the given request.
+ *
+ * @param request the HTTP request
+ * @return the resource name, or {@code null}/{@code ""} to skip Sentinel protection
+ */
+ String extractor(ClassicHttpRequest request);
+}
diff --git a/sentinel-adapter/sentinel-apache-httpclient5-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/apache/httpclient5/extractor/DefaultApacheHttpClientResourceExtractor.java b/sentinel-adapter/sentinel-apache-httpclient5-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/apache/httpclient5/extractor/DefaultApacheHttpClientResourceExtractor.java
new file mode 100644
index 0000000000..7f9fb3adb4
--- /dev/null
+++ b/sentinel-adapter/sentinel-apache-httpclient5-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/apache/httpclient5/extractor/DefaultApacheHttpClientResourceExtractor.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright 1999-2020 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
+ *
+ * http://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.apache.httpclient5.extractor;
+
+import com.alibaba.csp.sentinel.log.RecordLog;
+import org.apache.hc.core5.http.ClassicHttpRequest;
+
+/**
+ * Default implementation of {@link ApacheHttpClientResourceExtractor}.
+ *
+ * Generates resource name in the format {@code METHOD:url}, with query string
+ * and fragment stripped. This is consistent with the OkHttp adapter's resource naming
+ * convention.
+ *
+ * @author qihuai.wyq
+ */
+public class DefaultApacheHttpClientResourceExtractor implements ApacheHttpClientResourceExtractor {
+
+ @Override
+ public String extractor(ClassicHttpRequest request) {
+ try {
+ String httpMethod = request.getMethod();
+ String originalUrl = request.getUri().toString();
+ int firstIndexOfQuery = originalUrl.indexOf('?');
+ int firstIndexOfFragment = originalUrl.indexOf('#');
+ if (firstIndexOfFragment < 0 && firstIndexOfQuery < 0) {
+ return httpMethod + ":" + originalUrl;
+ }
+ if (firstIndexOfFragment > 0 && firstIndexOfQuery > 0) {
+ int pos = Math.min(firstIndexOfQuery, firstIndexOfFragment);
+ return httpMethod + ":" + originalUrl.substring(0, pos);
+ } else if (firstIndexOfQuery > 0) {
+ return httpMethod + ":" + originalUrl.substring(0, firstIndexOfQuery);
+ } else {
+ return httpMethod + ":" + originalUrl.substring(0, firstIndexOfFragment);
+ }
+ } catch (Exception ex) {
+ RecordLog.warn("Failed to extract resource name of HttpClient 5 request, request={}", request, ex);
+ return null;
+ }
+ }
+}
diff --git a/sentinel-adapter/sentinel-apache-httpclient5-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/apache/httpclient5/fallback/ApacheHttpClientFallback.java b/sentinel-adapter/sentinel-apache-httpclient5-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/apache/httpclient5/fallback/ApacheHttpClientFallback.java
new file mode 100644
index 0000000000..f3e890ed04
--- /dev/null
+++ b/sentinel-adapter/sentinel-apache-httpclient5-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/apache/httpclient5/fallback/ApacheHttpClientFallback.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright 1999-2020 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
+ *
+ * http://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.apache.httpclient5.fallback;
+
+import com.alibaba.csp.sentinel.slots.block.BlockException;
+import org.apache.hc.core5.http.ClassicHttpRequest;
+import org.apache.hc.core5.http.ClassicHttpResponse;
+
+/**
+ * Fallback handler for Apache HttpClient 5.x when the request is blocked by Sentinel.
+ *
+ * @author qihuai.wyq
+ */
+public interface ApacheHttpClientFallback {
+
+ /**
+ * Handle the blocked request.
+ *
+ * @param request the original HTTP request
+ * @param e the block exception
+ * @return the fallback response
+ */
+ ClassicHttpResponse handle(ClassicHttpRequest request, BlockException e);
+}
diff --git a/sentinel-adapter/sentinel-apache-httpclient5-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/apache/httpclient5/fallback/DefaultApacheHttpClientFallback.java b/sentinel-adapter/sentinel-apache-httpclient5-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/apache/httpclient5/fallback/DefaultApacheHttpClientFallback.java
new file mode 100644
index 0000000000..8136f3922c
--- /dev/null
+++ b/sentinel-adapter/sentinel-apache-httpclient5-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/apache/httpclient5/fallback/DefaultApacheHttpClientFallback.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright 1999-2020 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
+ *
+ * http://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.apache.httpclient5.fallback;
+
+import com.alibaba.csp.sentinel.slots.block.BlockException;
+import com.alibaba.csp.sentinel.slots.block.SentinelRpcException;
+import org.apache.hc.core5.http.ClassicHttpRequest;
+import org.apache.hc.core5.http.ClassicHttpResponse;
+
+/**
+ * @author qihuai.wyq
+ */
+public class DefaultApacheHttpClientFallback implements ApacheHttpClientFallback {
+
+ @Override
+ public ClassicHttpResponse handle(ClassicHttpRequest request, BlockException e) {
+ throw new SentinelRpcException(e);
+ }
+}
diff --git a/sentinel-adapter/sentinel-apache-httpclient5-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/apache/httpclient5/SentinelApacheHttpClientTest.java b/sentinel-adapter/sentinel-apache-httpclient5-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/apache/httpclient5/SentinelApacheHttpClientTest.java
new file mode 100644
index 0000000000..72234c6921
--- /dev/null
+++ b/sentinel-adapter/sentinel-apache-httpclient5-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/apache/httpclient5/SentinelApacheHttpClientTest.java
@@ -0,0 +1,168 @@
+/*
+ * Copyright 1999-2020 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
+ *
+ * http://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.apache.httpclient5;
+
+import com.alibaba.csp.sentinel.Constants;
+import com.alibaba.csp.sentinel.adapter.apache.httpclient5.app.TestApplication;
+import com.alibaba.csp.sentinel.adapter.apache.httpclient5.config.SentinelApacheHttpClientConfig;
+import com.alibaba.csp.sentinel.adapter.apache.httpclient5.extractor.ApacheHttpClientResourceExtractor;
+import com.alibaba.csp.sentinel.node.ClusterNode;
+import com.alibaba.csp.sentinel.slots.clusterbuilder.ClusterBuilderSlot;
+import org.apache.hc.client5.http.classic.methods.HttpGet;
+import org.apache.hc.client5.http.impl.ChainElement;
+import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
+import org.apache.hc.client5.http.impl.classic.CloseableHttpResponse;
+import org.apache.hc.client5.http.impl.classic.HttpClients;
+import org.apache.hc.core5.http.ClassicHttpRequest;
+import org.apache.hc.core5.http.HttpEntity;
+import org.apache.hc.core5.http.ParseException;
+import org.apache.hc.core5.http.io.entity.EntityUtils;
+import org.apache.hc.core5.http.protocol.BasicHttpContext;
+import org.apache.hc.core5.http.protocol.HttpContext;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.junit4.SpringRunner;
+
+import java.io.IOException;
+import java.net.URISyntaxException;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+
+/**
+ * @author qihuai.wyq
+ */
+@RunWith(SpringRunner.class)
+@SpringBootTest(classes = TestApplication.class,
+ webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT,
+ properties = {
+ "server.port=8185"
+ })
+public class SentinelApacheHttpClientTest {
+
+ @Value("${server.port}")
+ private Integer port;
+
+ @Test
+ public void testDefaultInterceptor() throws Exception {
+ CloseableHttpClient httpclient = HttpClients.custom()
+ .addExecInterceptorBefore(ChainElement.MAIN_TRANSPORT.name(), "sentinel",
+ new SentinelApacheHttpClient5Handler())
+ .build();
+
+ String url = "http://localhost:" + port + "/httpclient/back";
+ HttpGet httpGet = new HttpGet(url);
+ getRemoteString(httpclient, httpGet);
+ ClusterNode cn = ClusterBuilderSlot.getClusterNode("httpclient:GET:" + url);
+ assertNotNull(cn);
+ }
+
+ @Test
+ public void testWithUrlQuery() throws Exception {
+ CloseableHttpClient httpclient = HttpClients.custom()
+ .addExecInterceptorBefore(ChainElement.MAIN_TRANSPORT.name(), "sentinel",
+ new SentinelApacheHttpClient5Handler())
+ .build();
+
+ String urlWithQuery = "http://localhost:" + port + "/httpclient/query?foo=baz&baz=foo";
+ String urlWithoutQuery = "http://localhost:" + port + "/httpclient/query";
+ HttpGet httpGet = new HttpGet(urlWithQuery);
+ getRemoteString(httpclient, httpGet);
+ assertNotNull(ClusterBuilderSlot.getClusterNode("httpclient:GET:" + urlWithoutQuery));
+ assertNull(ClusterBuilderSlot.getClusterNode("httpclient:GET:" + urlWithQuery));
+ }
+
+ @Test
+ public void testWithUrlQueryAndFragment() throws Exception {
+ CloseableHttpClient httpclient = HttpClients.custom()
+ .addExecInterceptorBefore(ChainElement.MAIN_TRANSPORT.name(), "sentinel",
+ new SentinelApacheHttpClient5Handler())
+ .build();
+
+ String urlPrefix = "http://localhost:" + port + "/httpclient/fragment";
+ String suffix = "#foo?baz=xxx";
+ HttpGet httpGet = new HttpGet(urlPrefix + suffix);
+ getRemoteString(httpclient, httpGet);
+ assertNotNull(ClusterBuilderSlot.getClusterNode("httpclient:GET:" + urlPrefix));
+ assertNull(ClusterBuilderSlot.getClusterNode("httpclient:GET:" + urlPrefix + suffix));
+ }
+
+ @Test
+ public void testWithCustomizedResourceExtractor() throws Exception {
+ SentinelApacheHttpClientConfig config = new SentinelApacheHttpClientConfig();
+ config.setExtractor(new ApacheHttpClientResourceExtractor() {
+ @Override
+ public String extractor(ClassicHttpRequest request) {
+ String contains = "/httpclient/back/";
+ String uri;
+ try {
+ uri = request.getUri().toString();
+ } catch (URISyntaxException e) {
+ throw new RuntimeException(e);
+ }
+ if (uri.contains(contains)) {
+ uri = uri.substring(0, uri.indexOf(contains) + contains.length()) + "{id}";
+ }
+ return request.getMethod() + ":" + uri;
+ }
+ });
+ CloseableHttpClient httpclient = HttpClients.custom()
+ .addExecInterceptorBefore(ChainElement.MAIN_TRANSPORT.name(), "sentinel",
+ new SentinelApacheHttpClient5Handler(config))
+ .build();
+
+ HttpGet httpGet = new HttpGet("http://localhost:" + port + "/httpclient/back/1");
+ getRemoteString(httpclient, httpGet);
+ ClusterNode cn = ClusterBuilderSlot.getClusterNode(
+ "httpclient:GET:http://localhost:" + port + "/httpclient/back/{id}");
+ assertNotNull(cn);
+ }
+
+ @Test
+ public void testWithEmptyPrefix() throws Exception {
+ SentinelApacheHttpClientConfig config = new SentinelApacheHttpClientConfig();
+ config.setPrefix("");
+
+ CloseableHttpClient httpclient = HttpClients.custom()
+ .addExecInterceptorBefore(ChainElement.MAIN_TRANSPORT.name(), "sentinel",
+ new SentinelApacheHttpClient5Handler(config))
+ .build();
+
+ String url = "http://localhost:" + port + "/httpclient/noprefix";
+ HttpGet httpGet = new HttpGet(url);
+ getRemoteString(httpclient, httpGet);
+ ClusterNode cn = ClusterBuilderSlot.getClusterNode("GET:" + url);
+ assertNotNull(cn);
+ }
+
+ private String getRemoteString(CloseableHttpClient httpclient, HttpGet httpGet)
+ throws IOException, ParseException {
+ String result;
+ HttpContext context = new BasicHttpContext();
+ CloseableHttpResponse response = httpclient.execute(httpGet, context);
+ try {
+ HttpEntity entity = response.getEntity();
+ result = EntityUtils.toString(entity, "utf-8");
+ EntityUtils.consume(entity);
+ } finally {
+ response.close();
+ }
+ httpclient.close();
+ return result;
+ }
+}
diff --git a/sentinel-adapter/sentinel-apache-httpclient5-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/apache/httpclient5/app/TestApplication.java b/sentinel-adapter/sentinel-apache-httpclient5-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/apache/httpclient5/app/TestApplication.java
new file mode 100644
index 0000000000..a6d382ffaa
--- /dev/null
+++ b/sentinel-adapter/sentinel-apache-httpclient5-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/apache/httpclient5/app/TestApplication.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright 1999-2020 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
+ *
+ * http://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.apache.httpclient5.app;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+/**
+ * @author qihuai.wyq
+ */
+@SpringBootApplication
+public class TestApplication {
+
+ public static void main(String[] args) {
+ SpringApplication.run(TestApplication.class, args);
+ }
+}
diff --git a/sentinel-adapter/sentinel-apache-httpclient5-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/apache/httpclient5/app/controller/TestController.java b/sentinel-adapter/sentinel-apache-httpclient5-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/apache/httpclient5/app/controller/TestController.java
new file mode 100644
index 0000000000..f1e1eada37
--- /dev/null
+++ b/sentinel-adapter/sentinel-apache-httpclient5-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/apache/httpclient5/app/controller/TestController.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright 1999-2020 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
+ *
+ * http://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.apache.httpclient5.app.controller;
+
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * @author qihuai.wyq
+ */
+@RestController
+public class TestController {
+
+ @GetMapping("/httpclient/back")
+ public String back() {
+ return "Welcome Back!";
+ }
+
+ @GetMapping("/httpclient/back/{id}")
+ public String back(@PathVariable String id) {
+ return "Welcome Back!";
+ }
+
+ @GetMapping("/httpclient/query")
+ public String query() {
+ return "Query!";
+ }
+
+ @GetMapping("/httpclient/fragment")
+ public String fragment() {
+ return "Fragment!";
+ }
+
+ @GetMapping("/httpclient/noprefix")
+ public String noPrefix() {
+ return "No Prefix!";
+ }
+}
diff --git a/sentinel-adapter/sentinel-apache-httpclient5-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/apache/httpclient5/config/SentinelApacheHttpClientConfigTest.java b/sentinel-adapter/sentinel-apache-httpclient5-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/apache/httpclient5/config/SentinelApacheHttpClientConfigTest.java
new file mode 100644
index 0000000000..dbde163943
--- /dev/null
+++ b/sentinel-adapter/sentinel-apache-httpclient5-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/apache/httpclient5/config/SentinelApacheHttpClientConfigTest.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright 1999-2020 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
+ *
+ * http://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.apache.httpclient5.config;
+
+import com.alibaba.csp.sentinel.adapter.apache.httpclient5.extractor.DefaultApacheHttpClientResourceExtractor;
+import com.alibaba.csp.sentinel.adapter.apache.httpclient5.fallback.DefaultApacheHttpClientFallback;
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+/**
+ * @author qihuai.wyq
+ */
+public class SentinelApacheHttpClientConfigTest {
+
+ @Test
+ public void testDefaultConfig() {
+ SentinelApacheHttpClientConfig config = new SentinelApacheHttpClientConfig();
+ assertEquals("httpclient:", config.getPrefix());
+ assertNotNull(config.getExtractor());
+ assertNotNull(config.getFallback());
+ assertTrue(config.getExtractor() instanceof DefaultApacheHttpClientResourceExtractor);
+ assertTrue(config.getFallback() instanceof DefaultApacheHttpClientFallback);
+ }
+
+ @Test
+ public void testSetPrefix() {
+ SentinelApacheHttpClientConfig config = new SentinelApacheHttpClientConfig();
+ config.setPrefix("custom:");
+ assertEquals("custom:", config.getPrefix());
+ }
+
+ @Test
+ public void testSetEmptyPrefix() {
+ SentinelApacheHttpClientConfig config = new SentinelApacheHttpClientConfig();
+ config.setPrefix("");
+ assertEquals("", config.getPrefix());
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testSetNullPrefix() {
+ SentinelApacheHttpClientConfig config = new SentinelApacheHttpClientConfig();
+ config.setPrefix(null);
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testSetNullExtractor() {
+ SentinelApacheHttpClientConfig config = new SentinelApacheHttpClientConfig();
+ config.setExtractor(null);
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testSetNullFallback() {
+ SentinelApacheHttpClientConfig config = new SentinelApacheHttpClientConfig();
+ config.setFallback(null);
+ }
+}
diff --git a/sentinel-adapter/sentinel-apache-httpclient5-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/apache/httpclient5/extractor/DefaultApacheHttpClientResourceExtractorTest.java b/sentinel-adapter/sentinel-apache-httpclient5-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/apache/httpclient5/extractor/DefaultApacheHttpClientResourceExtractorTest.java
new file mode 100644
index 0000000000..93b70f3eb8
--- /dev/null
+++ b/sentinel-adapter/sentinel-apache-httpclient5-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/apache/httpclient5/extractor/DefaultApacheHttpClientResourceExtractorTest.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright 1999-2020 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
+ *
+ * http://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.apache.httpclient5.extractor;
+
+import org.apache.hc.client5.http.classic.methods.HttpGet;
+import org.apache.hc.client5.http.classic.methods.HttpPost;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+
+/**
+ * @author qihuai.wyq
+ */
+public class DefaultApacheHttpClientResourceExtractorTest {
+
+ private final DefaultApacheHttpClientResourceExtractor extractor =
+ new DefaultApacheHttpClientResourceExtractor();
+
+ @Test
+ public void testSimpleUrl() {
+ HttpGet request = new HttpGet("http://localhost:8080/api/users");
+ assertEquals("GET:http://localhost:8080/api/users", extractor.extractor(request));
+ }
+
+ @Test
+ public void testUrlWithQueryString() {
+ HttpGet request = new HttpGet("http://localhost:8080/api/users?page=1&size=10");
+ assertEquals("GET:http://localhost:8080/api/users", extractor.extractor(request));
+ }
+
+ @Test
+ public void testUrlWithFragment() {
+ HttpGet request = new HttpGet("http://localhost:8080/api/users#section");
+ assertEquals("GET:http://localhost:8080/api/users", extractor.extractor(request));
+ }
+
+ @Test
+ public void testUrlWithQueryAndFragment() {
+ HttpGet request = new HttpGet("http://localhost:8080/api/users?page=1#section");
+ assertEquals("GET:http://localhost:8080/api/users", extractor.extractor(request));
+ }
+
+ @Test
+ public void testUrlWithFragmentBeforeQuery() {
+ HttpGet request = new HttpGet("http://localhost:8080/api/users#section?page=1");
+ assertEquals("GET:http://localhost:8080/api/users", extractor.extractor(request));
+ }
+
+ @Test
+ public void testPostMethod() {
+ HttpPost request = new HttpPost("http://localhost:8080/api/users");
+ assertEquals("POST:http://localhost:8080/api/users", extractor.extractor(request));
+ }
+
+ @Test
+ public void testRootPath() {
+ HttpGet request = new HttpGet("http://localhost:8080/");
+ assertEquals("GET:http://localhost:8080/", extractor.extractor(request));
+ }
+
+ @Test
+ public void testRelativePath() {
+ HttpGet request = new HttpGet("/api/users");
+ assertEquals("GET:/api/users", extractor.extractor(request));
+ }
+
+ @Test
+ public void testRelativePathWithQuery() {
+ HttpGet request = new HttpGet("/api/users?page=1");
+ assertEquals("GET:/api/users", extractor.extractor(request));
+ }
+}
diff --git a/sentinel-adapter/sentinel-apache-httpclient5-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/apache/httpclient5/fallback/ApacheHttpClientFallbackTest.java b/sentinel-adapter/sentinel-apache-httpclient5-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/apache/httpclient5/fallback/ApacheHttpClientFallbackTest.java
new file mode 100644
index 0000000000..86d9be8862
--- /dev/null
+++ b/sentinel-adapter/sentinel-apache-httpclient5-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/apache/httpclient5/fallback/ApacheHttpClientFallbackTest.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright 1999-2020 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
+ *
+ * http://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.apache.httpclient5.fallback;
+
+import com.alibaba.csp.sentinel.slots.block.SentinelRpcException;
+import com.alibaba.csp.sentinel.slots.block.flow.FlowException;
+import org.apache.hc.client5.http.classic.methods.HttpGet;
+import org.junit.Test;
+
+/**
+ * @author qihuai.wyq
+ */
+public class ApacheHttpClientFallbackTest {
+
+ @Test(expected = SentinelRpcException.class)
+ public void testDefaultFallbackThrowsException() {
+ DefaultApacheHttpClientFallback fallback = new DefaultApacheHttpClientFallback();
+ HttpGet request = new HttpGet("http://localhost:8080/test");
+ fallback.handle(request, new FlowException("test"));
+ }
+}
From 37ab1cc2d9f77db5d266b938a2dd255b88bc177e Mon Sep 17 00:00:00 2001
From: uuuyuqi
Date: Sat, 21 Mar 2026 00:45:37 +0800
Subject: [PATCH 2/5] chore: bump version to 1.8.10-SNAPSHOT
After the 1.8.9 release, several PRs have been merged but
the development version was not updated. Bump to 1.8.10-SNAPSHOT
for next development iteration.
Change-Id: I2b7ba2b5b4e9e39d1f9749288d54b9926a512132
Co-developed-by: Cursor
---
pom.xml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/pom.xml b/pom.xml
index 423c71ad57..5c1cc2bb6d 100755
--- a/pom.xml
+++ b/pom.xml
@@ -40,7 +40,7 @@
- 1.8.9
+ 1.8.10-SNAPSHOT
1.2.83_noneautotype
1.3.2
From 0083d00f793d53f3cc065810243edace8b4f9b96 Mon Sep 17 00:00:00 2001
From: uuuyuqi
Date: Tue, 28 Apr 2026 15:05:48 +0800
Subject: [PATCH 3/5] fix: fix markdown table format to pass document-lint
Change-Id: I1fe4682e41185dc7c8ed30541989f2881ba87549
Co-developed-by: Cursor
---
sentinel-adapter/sentinel-apache-httpclient5-adapter/README.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/sentinel-adapter/sentinel-apache-httpclient5-adapter/README.md b/sentinel-adapter/sentinel-apache-httpclient5-adapter/README.md
index e7770c2779..f30a532c4e 100644
--- a/sentinel-adapter/sentinel-apache-httpclient5-adapter/README.md
+++ b/sentinel-adapter/sentinel-apache-httpclient5-adapter/README.md
@@ -42,7 +42,7 @@ CloseableHttpClient httpclient = HttpClients.custom()
### Configuration
| Name | Description | Type | Default Value |
-|------|------------|------|---------------|
+| --- | --- | --- | --- |
| prefix | Customize resource prefix | `String` | `httpclient:` |
| extractor | Customize resource extractor | `ApacheHttpClientResourceExtractor` | `DefaultApacheHttpClientResourceExtractor` |
| fallback | Handle request when it is blocked | `ApacheHttpClientFallback` | `DefaultApacheHttpClientFallback` |
From f9d1ce76a87c7173c280481e45aa9c8ad88c41b5 Mon Sep 17 00:00:00 2001
From: uuuyuqi
Date: Wed, 29 Apr 2026 10:20:24 +0800
Subject: [PATCH 4/5] fix: update @author from qihuai.wyq to uuuyuqi
Change-Id: Ie28f99434badfc00decc914ffd27f83c837d947d
Co-developed-by: Cursor
---
.vscode/settings.json | 3 +++
.../apache/httpclient5/SentinelApacheHttpClient5Handler.java | 2 +-
.../httpclient5/config/SentinelApacheHttpClientConfig.java | 2 +-
.../extractor/ApacheHttpClientResourceExtractor.java | 2 +-
.../extractor/DefaultApacheHttpClientResourceExtractor.java | 2 +-
.../apache/httpclient5/fallback/ApacheHttpClientFallback.java | 2 +-
.../httpclient5/fallback/DefaultApacheHttpClientFallback.java | 2 +-
.../apache/httpclient5/SentinelApacheHttpClientTest.java | 2 +-
.../adapter/apache/httpclient5/app/TestApplication.java | 2 +-
.../apache/httpclient5/app/controller/TestController.java | 2 +-
.../httpclient5/config/SentinelApacheHttpClientConfigTest.java | 2 +-
.../DefaultApacheHttpClientResourceExtractorTest.java | 2 +-
.../httpclient5/fallback/ApacheHttpClientFallbackTest.java | 2 +-
13 files changed, 15 insertions(+), 12 deletions(-)
create mode 100644 .vscode/settings.json
diff --git a/.vscode/settings.json b/.vscode/settings.json
new file mode 100644
index 0000000000..c5f3f6b9c7
--- /dev/null
+++ b/.vscode/settings.json
@@ -0,0 +1,3 @@
+{
+ "java.configuration.updateBuildConfiguration": "interactive"
+}
\ No newline at end of file
diff --git a/sentinel-adapter/sentinel-apache-httpclient5-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/apache/httpclient5/SentinelApacheHttpClient5Handler.java b/sentinel-adapter/sentinel-apache-httpclient5-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/apache/httpclient5/SentinelApacheHttpClient5Handler.java
index 2de5aa2f77..90018f2e67 100644
--- a/sentinel-adapter/sentinel-apache-httpclient5-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/apache/httpclient5/SentinelApacheHttpClient5Handler.java
+++ b/sentinel-adapter/sentinel-apache-httpclient5-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/apache/httpclient5/SentinelApacheHttpClient5Handler.java
@@ -45,7 +45,7 @@
* .build();
* }
*
- * @author qihuai.wyq
+ * @author uuuyuqi
*/
public class SentinelApacheHttpClient5Handler implements ExecChainHandler {
diff --git a/sentinel-adapter/sentinel-apache-httpclient5-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/apache/httpclient5/config/SentinelApacheHttpClientConfig.java b/sentinel-adapter/sentinel-apache-httpclient5-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/apache/httpclient5/config/SentinelApacheHttpClientConfig.java
index b52f49a056..d27bf903dc 100644
--- a/sentinel-adapter/sentinel-apache-httpclient5-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/apache/httpclient5/config/SentinelApacheHttpClientConfig.java
+++ b/sentinel-adapter/sentinel-apache-httpclient5-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/apache/httpclient5/config/SentinelApacheHttpClientConfig.java
@@ -22,7 +22,7 @@
import com.alibaba.csp.sentinel.util.AssertUtil;
/**
- * @author qihuai.wyq
+ * @author uuuyuqi
*/
public class SentinelApacheHttpClientConfig {
diff --git a/sentinel-adapter/sentinel-apache-httpclient5-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/apache/httpclient5/extractor/ApacheHttpClientResourceExtractor.java b/sentinel-adapter/sentinel-apache-httpclient5-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/apache/httpclient5/extractor/ApacheHttpClientResourceExtractor.java
index 94ab406022..e9e29df7c8 100644
--- a/sentinel-adapter/sentinel-apache-httpclient5-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/apache/httpclient5/extractor/ApacheHttpClientResourceExtractor.java
+++ b/sentinel-adapter/sentinel-apache-httpclient5-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/apache/httpclient5/extractor/ApacheHttpClientResourceExtractor.java
@@ -20,7 +20,7 @@
/**
* Extracts Sentinel resource name from an Apache HttpClient 5.x request.
*
- * @author qihuai.wyq
+ * @author uuuyuqi
*/
public interface ApacheHttpClientResourceExtractor {
diff --git a/sentinel-adapter/sentinel-apache-httpclient5-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/apache/httpclient5/extractor/DefaultApacheHttpClientResourceExtractor.java b/sentinel-adapter/sentinel-apache-httpclient5-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/apache/httpclient5/extractor/DefaultApacheHttpClientResourceExtractor.java
index 7f9fb3adb4..fba7636fe2 100644
--- a/sentinel-adapter/sentinel-apache-httpclient5-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/apache/httpclient5/extractor/DefaultApacheHttpClientResourceExtractor.java
+++ b/sentinel-adapter/sentinel-apache-httpclient5-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/apache/httpclient5/extractor/DefaultApacheHttpClientResourceExtractor.java
@@ -25,7 +25,7 @@
* and fragment stripped. This is consistent with the OkHttp adapter's resource naming
* convention.
*
- * @author qihuai.wyq
+ * @author uuuyuqi
*/
public class DefaultApacheHttpClientResourceExtractor implements ApacheHttpClientResourceExtractor {
diff --git a/sentinel-adapter/sentinel-apache-httpclient5-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/apache/httpclient5/fallback/ApacheHttpClientFallback.java b/sentinel-adapter/sentinel-apache-httpclient5-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/apache/httpclient5/fallback/ApacheHttpClientFallback.java
index f3e890ed04..60e42dc164 100644
--- a/sentinel-adapter/sentinel-apache-httpclient5-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/apache/httpclient5/fallback/ApacheHttpClientFallback.java
+++ b/sentinel-adapter/sentinel-apache-httpclient5-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/apache/httpclient5/fallback/ApacheHttpClientFallback.java
@@ -22,7 +22,7 @@
/**
* Fallback handler for Apache HttpClient 5.x when the request is blocked by Sentinel.
*
- * @author qihuai.wyq
+ * @author uuuyuqi
*/
public interface ApacheHttpClientFallback {
diff --git a/sentinel-adapter/sentinel-apache-httpclient5-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/apache/httpclient5/fallback/DefaultApacheHttpClientFallback.java b/sentinel-adapter/sentinel-apache-httpclient5-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/apache/httpclient5/fallback/DefaultApacheHttpClientFallback.java
index 8136f3922c..3637e7641e 100644
--- a/sentinel-adapter/sentinel-apache-httpclient5-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/apache/httpclient5/fallback/DefaultApacheHttpClientFallback.java
+++ b/sentinel-adapter/sentinel-apache-httpclient5-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/apache/httpclient5/fallback/DefaultApacheHttpClientFallback.java
@@ -21,7 +21,7 @@
import org.apache.hc.core5.http.ClassicHttpResponse;
/**
- * @author qihuai.wyq
+ * @author uuuyuqi
*/
public class DefaultApacheHttpClientFallback implements ApacheHttpClientFallback {
diff --git a/sentinel-adapter/sentinel-apache-httpclient5-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/apache/httpclient5/SentinelApacheHttpClientTest.java b/sentinel-adapter/sentinel-apache-httpclient5-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/apache/httpclient5/SentinelApacheHttpClientTest.java
index 72234c6921..77d1eb5c2c 100644
--- a/sentinel-adapter/sentinel-apache-httpclient5-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/apache/httpclient5/SentinelApacheHttpClientTest.java
+++ b/sentinel-adapter/sentinel-apache-httpclient5-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/apache/httpclient5/SentinelApacheHttpClientTest.java
@@ -45,7 +45,7 @@
import static org.junit.Assert.assertNull;
/**
- * @author qihuai.wyq
+ * @author uuuyuqi
*/
@RunWith(SpringRunner.class)
@SpringBootTest(classes = TestApplication.class,
diff --git a/sentinel-adapter/sentinel-apache-httpclient5-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/apache/httpclient5/app/TestApplication.java b/sentinel-adapter/sentinel-apache-httpclient5-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/apache/httpclient5/app/TestApplication.java
index a6d382ffaa..f3cfaa4222 100644
--- a/sentinel-adapter/sentinel-apache-httpclient5-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/apache/httpclient5/app/TestApplication.java
+++ b/sentinel-adapter/sentinel-apache-httpclient5-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/apache/httpclient5/app/TestApplication.java
@@ -19,7 +19,7 @@
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
- * @author qihuai.wyq
+ * @author uuuyuqi
*/
@SpringBootApplication
public class TestApplication {
diff --git a/sentinel-adapter/sentinel-apache-httpclient5-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/apache/httpclient5/app/controller/TestController.java b/sentinel-adapter/sentinel-apache-httpclient5-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/apache/httpclient5/app/controller/TestController.java
index f1e1eada37..12ecb0756e 100644
--- a/sentinel-adapter/sentinel-apache-httpclient5-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/apache/httpclient5/app/controller/TestController.java
+++ b/sentinel-adapter/sentinel-apache-httpclient5-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/apache/httpclient5/app/controller/TestController.java
@@ -20,7 +20,7 @@
import org.springframework.web.bind.annotation.RestController;
/**
- * @author qihuai.wyq
+ * @author uuuyuqi
*/
@RestController
public class TestController {
diff --git a/sentinel-adapter/sentinel-apache-httpclient5-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/apache/httpclient5/config/SentinelApacheHttpClientConfigTest.java b/sentinel-adapter/sentinel-apache-httpclient5-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/apache/httpclient5/config/SentinelApacheHttpClientConfigTest.java
index dbde163943..4b15fadd4e 100644
--- a/sentinel-adapter/sentinel-apache-httpclient5-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/apache/httpclient5/config/SentinelApacheHttpClientConfigTest.java
+++ b/sentinel-adapter/sentinel-apache-httpclient5-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/apache/httpclient5/config/SentinelApacheHttpClientConfigTest.java
@@ -22,7 +22,7 @@
import static org.junit.Assert.*;
/**
- * @author qihuai.wyq
+ * @author uuuyuqi
*/
public class SentinelApacheHttpClientConfigTest {
diff --git a/sentinel-adapter/sentinel-apache-httpclient5-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/apache/httpclient5/extractor/DefaultApacheHttpClientResourceExtractorTest.java b/sentinel-adapter/sentinel-apache-httpclient5-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/apache/httpclient5/extractor/DefaultApacheHttpClientResourceExtractorTest.java
index 93b70f3eb8..bc8ccb446b 100644
--- a/sentinel-adapter/sentinel-apache-httpclient5-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/apache/httpclient5/extractor/DefaultApacheHttpClientResourceExtractorTest.java
+++ b/sentinel-adapter/sentinel-apache-httpclient5-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/apache/httpclient5/extractor/DefaultApacheHttpClientResourceExtractorTest.java
@@ -22,7 +22,7 @@
import static org.junit.Assert.assertEquals;
/**
- * @author qihuai.wyq
+ * @author uuuyuqi
*/
public class DefaultApacheHttpClientResourceExtractorTest {
diff --git a/sentinel-adapter/sentinel-apache-httpclient5-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/apache/httpclient5/fallback/ApacheHttpClientFallbackTest.java b/sentinel-adapter/sentinel-apache-httpclient5-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/apache/httpclient5/fallback/ApacheHttpClientFallbackTest.java
index 86d9be8862..a2640ec6ec 100644
--- a/sentinel-adapter/sentinel-apache-httpclient5-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/apache/httpclient5/fallback/ApacheHttpClientFallbackTest.java
+++ b/sentinel-adapter/sentinel-apache-httpclient5-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/apache/httpclient5/fallback/ApacheHttpClientFallbackTest.java
@@ -21,7 +21,7 @@
import org.junit.Test;
/**
- * @author qihuai.wyq
+ * @author uuuyuqi
*/
public class ApacheHttpClientFallbackTest {
From fe82273e206aeac61277efc660d3b4bd5bfa15c0 Mon Sep 17 00:00:00 2001
From: uuuyuqi
Date: Wed, 29 Apr 2026 10:20:41 +0800
Subject: [PATCH 5/5] chore: remove accidentally committed
.vscode/settings.json
Change-Id: I60caec5b17e92a79827671e531a0818f61163b48
Co-developed-by: Cursor
---
.vscode/settings.json | 3 ---
1 file changed, 3 deletions(-)
delete mode 100644 .vscode/settings.json
diff --git a/.vscode/settings.json b/.vscode/settings.json
deleted file mode 100644
index c5f3f6b9c7..0000000000
--- a/.vscode/settings.json
+++ /dev/null
@@ -1,3 +0,0 @@
-{
- "java.configuration.updateBuildConfiguration": "interactive"
-}
\ No newline at end of file