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());