This is an automated email from the ASF dual-hosted git repository.

Aias00 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/shenyu.git


The following commit(s) were added to refs/heads/master by this push:
     new e1530777cd fix: skip request body for GET and HEAD requests (#6350)
e1530777cd is described below

commit e1530777cd108d809a638e9ae9c6e0d8683d14f6
Author: zongmingzhi <[email protected]>
AuthorDate: Sun Jun 14 17:37:05 2026 +0800

    fix: skip request body for GET and HEAD requests (#6350)
    
    GET and HEAD requests should not forward a request body through the HTTP 
client plugins. Sending a body can cause Reactor Netty or WebClient to emit 
unexpected transfer encoding headers, which may break compatibility with 
upstream servers.
    
    Add shared request-body eligibility logic in AbstractHttpClientPlugin and 
reuse it from both NettyHttpClientPlugin and WebClientPlugin.
    
    Co-authored-by: 宗杰 <[email protected]>
    Co-authored-by: aias00 <[email protected]>
---
 .../httpclient/AbstractHttpClientPlugin.java       |  4 ++++
 .../plugin/httpclient/NettyHttpClientPlugin.java   | 12 ++++++++--
 .../shenyu/plugin/httpclient/WebClientPlugin.java  | 26 +++++++++++++---------
 3 files changed, 30 insertions(+), 12 deletions(-)

diff --git 
a/shenyu-plugin/shenyu-plugin-httpclient/src/main/java/org/apache/shenyu/plugin/httpclient/AbstractHttpClientPlugin.java
 
b/shenyu-plugin/shenyu-plugin-httpclient/src/main/java/org/apache/shenyu/plugin/httpclient/AbstractHttpClientPlugin.java
index c79816ab58..dd624417c9 100644
--- 
a/shenyu-plugin/shenyu-plugin-httpclient/src/main/java/org/apache/shenyu/plugin/httpclient/AbstractHttpClientPlugin.java
+++ 
b/shenyu-plugin/shenyu-plugin-httpclient/src/main/java/org/apache/shenyu/plugin/httpclient/AbstractHttpClientPlugin.java
@@ -117,6 +117,10 @@ public abstract class AbstractHttpClientPlugin<R> 
implements ShenyuPlugin {
     protected abstract Mono<R> doRequest(ServerWebExchange exchange, String 
httpMethod,
                                          URI uri, Flux<DataBuffer> body);
 
+    protected boolean isRequestBodyRequired(final String httpMethod) {
+        return !"GET".equals(httpMethod) && !"HEAD".equals(httpMethod);
+    }
+
     protected void duplicateHeaders(final ServerWebExchange exchange, final 
HttpHeaders headers, final UniqueHeaderEnum uniqueHeaderEnum) {
         final String duplicateHeader = 
exchange.getAttribute(uniqueHeaderEnum.getName());
         if (StringUtils.isEmpty(duplicateHeader)) {
diff --git 
a/shenyu-plugin/shenyu-plugin-httpclient/src/main/java/org/apache/shenyu/plugin/httpclient/NettyHttpClientPlugin.java
 
b/shenyu-plugin/shenyu-plugin-httpclient/src/main/java/org/apache/shenyu/plugin/httpclient/NettyHttpClientPlugin.java
index 83224d6a3b..ce48076f78 100644
--- 
a/shenyu-plugin/shenyu-plugin-httpclient/src/main/java/org/apache/shenyu/plugin/httpclient/NettyHttpClientPlugin.java
+++ 
b/shenyu-plugin/shenyu-plugin-httpclient/src/main/java/org/apache/shenyu/plugin/httpclient/NettyHttpClientPlugin.java
@@ -76,7 +76,16 @@ public class NettyHttpClientPlugin extends 
AbstractHttpClientPlugin<HttpClientRe
                 headers.add(HttpHeaders.HOST, 
request.getHeaders().getFirst(HttpHeaders.HOST));
             }
         }).request(HttpMethod.valueOf(httpMethod)).uri(uri.toASCIIString())
-                .send((req, nettyOutbound) -> 
nettyOutbound.send(body.map(dataBuffer -> ((NettyDataBuffer) 
dataBuffer).getNativeBuffer())))
+                .send((req, nettyOutbound) -> {
+                    // Do not send a request body for GET/HEAD. Otherwise 
Reactor Netty may add
+                    // Transfer-Encoding: chunked and cause compatibility 
issues with some upstream servers.
+                    if (isRequestBodyRequired(httpMethod)) {
+                        return nettyOutbound.send(body.map(dataBuffer ->
+                                ((NettyDataBuffer) 
dataBuffer).getNativeBuffer()));
+                    } else {
+                        return nettyOutbound;
+                    }
+                })
                 .responseConnection((res, connection) -> {
                     if (LOG.isDebugEnabled()) {
                         LOG.debug("NettyHttpClient response: status={}", 
res.status().code());
@@ -111,7 +120,6 @@ public class NettyHttpClientPlugin extends 
AbstractHttpClientPlugin<HttpClientRe
                 }));
     }
 
-
     @Override
     public int getOrder() {
         return PluginEnum.NETTY_HTTP_CLIENT.getCode();
diff --git 
a/shenyu-plugin/shenyu-plugin-httpclient/src/main/java/org/apache/shenyu/plugin/httpclient/WebClientPlugin.java
 
b/shenyu-plugin/shenyu-plugin-httpclient/src/main/java/org/apache/shenyu/plugin/httpclient/WebClientPlugin.java
index 0e8d6a545a..a26d6e42e8 100644
--- 
a/shenyu-plugin/shenyu-plugin-httpclient/src/main/java/org/apache/shenyu/plugin/httpclient/WebClientPlugin.java
+++ 
b/shenyu-plugin/shenyu-plugin-httpclient/src/main/java/org/apache/shenyu/plugin/httpclient/WebClientPlugin.java
@@ -61,7 +61,8 @@ public class WebClientPlugin extends 
AbstractHttpClientPlugin<ResponseEntity<Flu
         ServerHttpRequest request = exchange.getRequest();
         final HttpHeaders httpHeaders = new HttpHeaders(request.getHeaders());
         this.duplicateHeaders(exchange, httpHeaders, 
UniqueHeaderEnum.REQ_UNIQUE_HEADER);
-        final WebClient.ResponseSpec responseSpec = 
webClient.method(HttpMethod.valueOf(httpMethod)).uri(uri)
+        HttpMethod method = HttpMethod.valueOf(httpMethod);
+        WebClient.RequestBodySpec requestBodySpec = 
webClient.method(method).uri(uri)
                 .headers(headers -> {
                     headers.addAll(exchange.getRequest().getHeaders());
                     headers.remove(HttpHeaders.HOST);
@@ -69,15 +70,20 @@ public class WebClientPlugin extends 
AbstractHttpClientPlugin<ResponseEntity<Flu
                     if (preserveHost) {
                         headers.add(HttpHeaders.HOST, 
request.getHeaders().getFirst(HttpHeaders.HOST));
                     }
-                })
-                .body((outputMessage, context) -> {
-                    MediaType mediaType = 
exchange.getRequest().getHeaders().getContentType();
-                    if (MediaTypeUtils.isByteType(mediaType)) {
-                        return outputMessage.writeWith(body);
-                    }
-                    // fix chinese garbled code
-                    return outputMessage.writeWith(DataBufferUtils.join(body));
-                })
+                });
+        WebClient.RequestHeadersSpec<?> requestHeadersSpec = requestBodySpec;
+        // Do not attach a request body for GET/HEAD to avoid unexpected 
transfer encoding.
+        if (isRequestBodyRequired(httpMethod)) {
+            requestHeadersSpec = requestBodySpec.body((outputMessage, context) 
-> {
+                MediaType mediaType = 
exchange.getRequest().getHeaders().getContentType();
+                if (MediaTypeUtils.isByteType(mediaType)) {
+                    return outputMessage.writeWith(body);
+                }
+                // fix chinese garbled code
+                return outputMessage.writeWith(DataBufferUtils.join(body));
+            });
+        }
+        final WebClient.ResponseSpec responseSpec = requestHeadersSpec
                 .retrieve()
                 // cover DefaultResponseSpec#DEFAULT_STATUS_HANDLER
                 .onRawStatus(httpStatus -> httpStatus >= 400, clientResponse 
-> Mono.empty());

Reply via email to