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

zhangzicheng 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 c46ceed3f [ISSUE #3773] use #exchangeToMono replace #exchange (#3792)
c46ceed3f is described below

commit c46ceed3f5c098187fee0d8919110d9ac37a29e3
Author: dragon-zhang <[email protected]>
AuthorDate: Fri Sep 2 22:53:02 2022 +0800

    [ISSUE #3773] use #exchangeToMono replace #exchange (#3792)
    
    * [ISSUE #3773] use #exchangeToMono replace #exchange
    
    * clean DataBuffer
    
    * use Optional
    
    * fix test case
    
    * use Mono.fromCallable
    
    * add cookies
---
 .../shenyu/plugin/httpclient/WebClientPlugin.java  | 30 ++++++++++++++--------
 .../plugin/httpclient/WebClientPluginTest.java     | 13 ++++++++++
 2 files changed, 33 insertions(+), 10 deletions(-)

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 3f81fe431..72ad7eb14 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
@@ -21,6 +21,7 @@ import org.apache.shenyu.common.constant.Constants;
 import org.apache.shenyu.common.enums.PluginEnum;
 import org.apache.shenyu.common.enums.ResultEnum;
 import org.springframework.core.io.buffer.DataBuffer;
+import org.springframework.core.io.buffer.DataBufferFactory;
 import org.springframework.http.HttpHeaders;
 import org.springframework.http.HttpMethod;
 import org.springframework.web.reactive.function.BodyInserters;
@@ -31,14 +32,15 @@ import reactor.core.publisher.Flux;
 import reactor.core.publisher.Mono;
 
 import java.net.URI;
+import java.util.Optional;
 
 /**
  * The type Web client plugin.
  */
 public class WebClientPlugin extends AbstractHttpClientPlugin<ClientResponse> {
-
+    
     private final WebClient webClient;
-
+    
     /**
      * Instantiates a new Web client plugin.
      *
@@ -47,20 +49,28 @@ public class WebClientPlugin extends 
AbstractHttpClientPlugin<ClientResponse> {
     public WebClientPlugin(final WebClient webClient) {
         this.webClient = webClient;
     }
-
+    
     @Override
     protected Mono<ClientResponse> doRequest(final ServerWebExchange exchange, 
final String httpMethod, final URI uri,
                                              final HttpHeaders httpHeaders, 
final Flux<DataBuffer> body) {
         // springWebflux5.3 mark #exchange() deprecated. because #echange 
maybe make memory leak.
         // https://github.com/spring-projects/spring-framework/issues/25751
         // exchange is deprecated, so change to {@link 
WebClient.RequestHeadersSpec#exchangeToMono(Function)}
-        // exchangeToMono has two important bug:
-        // 1.exchangeToMono can cause NPE when response body is null
-        // 2.download file with exchangeToMono can't open
         return webClient.method(HttpMethod.valueOf(httpMethod)).uri(uri)
                 .headers(headers -> headers.addAll(httpHeaders))
                 .body(BodyInserters.fromDataBuffers(body))
-                .exchange()
+                .exchangeToMono(response -> response.bodyToMono(byte[].class)
+                        .flatMap(bytes -> Mono.fromCallable(() -> 
Optional.ofNullable(bytes))).defaultIfEmpty(Optional.empty())
+                        .flatMap(option -> {
+                            final ClientResponse.Builder builder = 
ClientResponse.create(response.statusCode())
+                                    .headers(headers -> 
headers.addAll(response.headers().asHttpHeaders()))
+                                    .cookies(cookies -> 
cookies.addAll(response.cookies()));
+                            if (option.isPresent()) {
+                                final DataBufferFactory dataBufferFactory = 
exchange.getResponse().bufferFactory();
+                                return 
Mono.just(builder.body(Flux.just(dataBufferFactory.wrap(option.get()))).build());
+                            }
+                            return Mono.just(builder.build());
+                        }))
                 .doOnSuccess(res -> {
                     if (res.statusCode().is2xxSuccessful()) {
                         
exchange.getAttributes().put(Constants.CLIENT_RESPONSE_RESULT_TYPE, 
ResultEnum.SUCCESS.getName());
@@ -71,17 +81,17 @@ public class WebClientPlugin extends 
AbstractHttpClientPlugin<ClientResponse> {
                     
exchange.getAttributes().put(Constants.CLIENT_RESPONSE_ATTR, res);
                 });
     }
-
+    
     @Override
     public int getOrder() {
         return PluginEnum.WEB_CLIENT.getCode();
     }
-
+    
     @Override
     public String named() {
         return PluginEnum.WEB_CLIENT.getName();
     }
-
+    
     @Override
     public boolean skip(final ServerWebExchange exchange) {
         return skipExceptHttpLike(exchange);
diff --git 
a/shenyu-plugin/shenyu-plugin-httpclient/src/test/java/org/apache/shenyu/plugin/httpclient/WebClientPluginTest.java
 
b/shenyu-plugin/shenyu-plugin-httpclient/src/test/java/org/apache/shenyu/plugin/httpclient/WebClientPluginTest.java
index f029c6a95..2b26962a8 100644
--- 
a/shenyu-plugin/shenyu-plugin-httpclient/src/test/java/org/apache/shenyu/plugin/httpclient/WebClientPluginTest.java
+++ 
b/shenyu-plugin/shenyu-plugin-httpclient/src/test/java/org/apache/shenyu/plugin/httpclient/WebClientPluginTest.java
@@ -34,6 +34,7 @@ import org.mockito.junit.jupiter.MockitoExtension;
 import org.mockito.junit.jupiter.MockitoSettings;
 import org.mockito.quality.Strictness;
 import org.springframework.context.ConfigurableApplicationContext;
+import org.springframework.http.HttpHeaders;
 import org.springframework.http.HttpStatus;
 import org.springframework.mock.http.server.reactive.MockServerHttpRequest;
 import org.springframework.mock.web.server.MockServerWebExchange;
@@ -159,8 +160,14 @@ public final class WebClientPluginTest {
     }
 
     private WebClient mockWebClientOK() {
+        final ClientResponse.Headers headers = 
mock(ClientResponse.Headers.class);
+        when(headers.asHttpHeaders()).thenReturn(new HttpHeaders());
+        
         final ClientResponse mockResponse = mock(ClientResponse.class);
         when(mockResponse.statusCode()).thenReturn(HttpStatus.OK);
+        when(mockResponse.headers()).thenReturn(headers);
+        
when(mockResponse.bodyToMono(byte[].class)).thenReturn(Mono.just("{\"test\":\"ok\"}".getBytes()));
+        when(mockResponse.releaseBody()).thenReturn(Mono.empty());
         
given(this.exchangeFunction.exchange(this.captor.capture())).willReturn(Mono.just(mockResponse));
         return WebClient.builder().baseUrl("/test")
                 .exchangeFunction(this.exchangeFunction)
@@ -170,8 +177,14 @@ public final class WebClientPluginTest {
     }
 
     private WebClient mockWebClientError() {
+        final ClientResponse.Headers headers = 
mock(ClientResponse.Headers.class);
+        when(headers.asHttpHeaders()).thenReturn(new HttpHeaders());
+        
         final ClientResponse mockResponse = mock(ClientResponse.class);
         
when(mockResponse.statusCode()).thenReturn(HttpStatus.INTERNAL_SERVER_ERROR);
+        when(mockResponse.headers()).thenReturn(headers);
+        when(mockResponse.bodyToMono(byte[].class)).thenReturn(Mono.just(new 
byte[0]));
+        when(mockResponse.releaseBody()).thenReturn(Mono.empty());
         
given(this.exchangeFunction.exchange(this.captor.capture())).willReturn(Mono.just(mockResponse));
         return WebClient.builder().baseUrl("/test")
                 .exchangeFunction(this.exchangeFunction)

Reply via email to