diff --git a/spring-cloud-gateway-mvc/src/main/java/org/springframework/cloud/gateway/mvc/ProxyExchange.java b/spring-cloud-gateway-mvc/src/main/java/org/springframework/cloud/gateway/mvc/ProxyExchange.java index 49c88da2..e1bb63f8 100644 --- a/spring-cloud-gateway-mvc/src/main/java/org/springframework/cloud/gateway/mvc/ProxyExchange.java +++ b/spring-cloud-gateway-mvc/src/main/java/org/springframework/cloud/gateway/mvc/ProxyExchange.java @@ -415,7 +415,7 @@ public class ProxyExchange { } private String forwarded(URI uri, String hostHeader) { - if (!StringUtils.isEmpty(hostHeader)) { + if (StringUtils.hasText(hostHeader)) { return "host=" + hostHeader; } if ("http".equals(uri.getScheme())) { @@ -570,7 +570,7 @@ class ServletOutputToInputConverter extends HttpServletResponseWrapper { @Override public void write(int b) throws IOException { - builder.append(new Character((char) b)); + builder.append(Character.valueOf((char) b)); } @Override diff --git a/spring-cloud-gateway-mvc/src/test/java/org/springframework/cloud/gateway/mvc/ProductionConfigurationTests.java b/spring-cloud-gateway-mvc/src/test/java/org/springframework/cloud/gateway/mvc/ProductionConfigurationTests.java index 74eb4c6e..3f905c08 100644 --- a/spring-cloud-gateway-mvc/src/test/java/org/springframework/cloud/gateway/mvc/ProductionConfigurationTests.java +++ b/spring-cloud-gateway-mvc/src/test/java/org/springframework/cloud/gateway/mvc/ProductionConfigurationTests.java @@ -74,61 +74,61 @@ public class ProductionConfigurationTests { private int port; @Before - public void init() throws Exception { - application.setHome(new URI("http://localhost:" + port)); + public void init() { + application.setHome(URI.create("http://localhost:" + port)); rest.getRestTemplate().setRequestFactory(new SimpleClientHttpRequestFactory()); } @Test - public void get() throws Exception { + public void get() { assertThat(rest.getForObject("/proxy/0", Foo.class).getName()).isEqualTo("bye"); } @Test - public void path() throws Exception { + public void path() { assertThat(rest.getForObject("/proxy/path/1", Foo.class).getName()).isEqualTo("foo"); } @Test - public void resource() throws Exception { + public void resource() { assertThat(rest.getForObject("/proxy/html/test.html", String.class)).contains("Test"); } @Test - public void resourceWithNoType() throws Exception { + public void resourceWithNoType() { assertThat(rest.getForObject("/proxy/typeless/test.html", String.class)).contains("Test"); } @Test - public void missing() throws Exception { + public void missing() { assertThat(rest.getForEntity("/proxy/missing/0", Foo.class).getStatusCode()).isEqualTo(HttpStatus.NOT_FOUND); } @Test - public void uri() throws Exception { + public void uri() { assertThat(rest.getForObject("/proxy/0", Foo.class).getName()).isEqualTo("bye"); } @Test - public void post() throws Exception { + public void post() { assertThat(rest.postForObject("/proxy/0", Collections.singletonMap("name", "foo"), Bar.class).getName()) .isEqualTo("host=localhost:" + port + ";foo"); } @Test - public void forward() throws Exception { + public void forward() { assertThat(rest.getForObject("/forward/foos/0", Foo.class).getName()).isEqualTo("bye"); } @Test - public void forwardHeader() throws Exception { + public void forwardHeader() { ResponseEntity result = rest.getForEntity("/forward/special/foos/0", Foo.class); assertThat(result.getStatusCode()).isEqualTo(HttpStatus.OK); assertThat(result.getBody().getName()).isEqualTo("FOO"); } @Test - public void postForwardHeader() throws Exception { + public void postForwardHeader() { ResponseEntity> result = rest.exchange( RequestEntity.post(rest.getRestTemplate().getUriTemplateHandler().expand("/forward/special/bars")) .body(Collections.singletonList(Collections.singletonMap("name", "foo"))), @@ -139,7 +139,7 @@ public class ProductionConfigurationTests { } @Test - public void postForwardBody() throws Exception { + public void postForwardBody() { ResponseEntity result = rest .exchange( RequestEntity.post(rest.getRestTemplate().getUriTemplateHandler().expand("/forward/body/bars")) @@ -150,7 +150,7 @@ public class ProductionConfigurationTests { } @Test - public void postForwardForgetBody() throws Exception { + public void postForwardForgetBody() { ResponseEntity result = rest.exchange( RequestEntity.post(rest.getRestTemplate().getUriTemplateHandler().expand("/forward/forget/bars")) .body(Collections.singletonList(Collections.singletonMap("name", "foo"))), @@ -160,7 +160,7 @@ public class ProductionConfigurationTests { } @Test - public void postForwardBodyFoo() throws Exception { + public void postForwardBodyFoo() { ResponseEntity> result = rest.exchange( RequestEntity.post(rest.getRestTemplate().getUriTemplateHandler().expand("/forward/body/bars")) .body(Collections.singletonList(Collections.singletonMap("name", "foo"))), @@ -171,7 +171,7 @@ public class ProductionConfigurationTests { } @Test - public void list() throws Exception { + public void list() { assertThat(rest.exchange( RequestEntity.post(rest.getRestTemplate().getUriTemplateHandler().expand("/proxy")) .body(Collections.singletonList(Collections.singletonMap("name", "foo"))), @@ -180,13 +180,13 @@ public class ProductionConfigurationTests { } @Test - public void bodyless() throws Exception { + public void bodyless() { assertThat(rest.postForObject("/proxy/0", Collections.singletonMap("name", "foo"), Bar.class).getName()) .isEqualTo("host=localhost:" + port + ";foo"); } @Test - public void entity() throws Exception { + public void entity() { assertThat( rest.exchange(RequestEntity.post(rest.getRestTemplate().getUriTemplateHandler().expand("/proxy/entity")) .body(Collections.singletonMap("name", "foo")), new ParameterizedTypeReference>() { @@ -194,7 +194,7 @@ public class ProductionConfigurationTests { } @Test - public void entityWithType() throws Exception { + public void entityWithType() { assertThat( rest.exchange(RequestEntity.post(rest.getRestTemplate().getUriTemplateHandler().expand("/proxy/type")) .body(Collections.singletonMap("name", "foo")), new ParameterizedTypeReference>() { @@ -202,45 +202,45 @@ public class ProductionConfigurationTests { } @Test - public void single() throws Exception { + public void single() { assertThat(rest.postForObject("/proxy/single", Collections.singletonMap("name", "foobar"), Bar.class).getName()) .isEqualTo("host=localhost:" + port + ";foobar"); } @Test - public void converter() throws Exception { + public void converter() { assertThat( rest.postForObject("/proxy/converter", Collections.singletonMap("name", "foobar"), Bar.class).getName()) .isEqualTo("host=localhost:" + port + ";foobar"); } @Test - public void noBody() throws Exception { + public void noBody() { Foo foo = rest.postForObject("/proxy/no-body", null, Foo.class); assertThat(foo.getName()).isEqualTo("hello"); } @Test - public void deleteWithoutBody() throws Exception { + public void deleteWithoutBody() { ResponseEntity deleteResponse = rest.exchange("/proxy/{id}/no-body", HttpMethod.DELETE, null, Void.TYPE, Collections.singletonMap("id", "123")); assertThat(deleteResponse.getStatusCode()).isEqualTo(HttpStatus.OK); } @Test - public void deleteWithBody() throws Exception { + public void deleteWithBody() { Foo foo = new Foo("to-be-deleted"); ParameterizedTypeReference> returnType = new ParameterizedTypeReference>() { }; ResponseEntity> deleteResponse = rest.exchange("/proxy/{id}", HttpMethod.DELETE, new HttpEntity(foo), returnType, Collections.singletonMap("id", "123")); assertThat(deleteResponse.getStatusCode()).isEqualTo(HttpStatus.OK); - assertThat(deleteResponse.getBody().get("deleted")).isEqualToComparingFieldByField(foo); + assertThat(deleteResponse.getBody().get("deleted")).usingRecursiveComparison().isEqualTo(foo); } @Test @SuppressWarnings({ "Duplicates", "unchecked" }) - public void testSensitiveHeadersOverride() throws Exception { + public void testSensitiveHeadersOverride() { RequestEntity request = RequestEntity .get(rest.getRestTemplate().getUriTemplateHandler().expand("/proxy/headers")).header("foo", "bar") .header("abc", "xyz").header("cookie", "monster").build(); @@ -252,7 +252,7 @@ public class ProductionConfigurationTests { @Test @SuppressWarnings({ "Duplicates", "unchecked" }) - public void testSensitiveHeadersDefault() throws Exception { + public void testSensitiveHeadersDefault() { Map> headers = rest.exchange(RequestEntity .get(rest.getRestTemplate().getUriTemplateHandler().expand("/proxy/sensitive-headers-default")) .header("cookie", "monster").build(), Map.class).getBody(); @@ -262,7 +262,7 @@ public class ProductionConfigurationTests { @Test @SuppressWarnings({ "Duplicates", "unchecked" }) - public void headers() throws Exception { + public void headers() { Map> headers = rest .exchange(RequestEntity.get(rest.getRestTemplate().getUriTemplateHandler().expand("/proxy/headers")) .header("foo", "bar").header("abc", "xyz").header("baz", "fob").build(), Map.class) @@ -275,7 +275,7 @@ public class ProductionConfigurationTests { } @Test - public void forwardedHeaderUsesHost() throws Exception { + public void forwardedHeaderUsesHost() { Map> headers = rest .exchange(RequestEntity.get(rest.getRestTemplate().getUriTemplateHandler().expand("/proxy/headers")) .header("host", "foo:1234").build(), Map.class) @@ -306,97 +306,93 @@ public class ProductionConfigurationTests { } @GetMapping("/proxy/{id}") - public ResponseEntity proxyFoos(@PathVariable Integer id, ProxyExchange proxy) throws Exception { + public ResponseEntity proxyFoos(@PathVariable Integer id, ProxyExchange proxy) { return proxy.uri(home.toString() + "/foos/" + id).get(); } @GetMapping("/proxy/path/**") - public ResponseEntity proxyPath(ProxyExchange proxy, UriComponentsBuilder uri) throws Exception { + public ResponseEntity proxyPath(ProxyExchange proxy, UriComponentsBuilder uri) { String path = proxy.path("/proxy/path/"); return proxy.uri(home.toString() + "/foos/" + path).get(); } @GetMapping("/proxy/html/**") - public ResponseEntity proxyHtml(ProxyExchange proxy, UriComponentsBuilder uri) - throws Exception { + public ResponseEntity proxyHtml(ProxyExchange proxy, UriComponentsBuilder uri) { String path = proxy.path("/proxy/html"); return proxy.uri(home.toString() + path).get(); } @GetMapping("/proxy/typeless/**") - public ResponseEntity proxyTypeless(ProxyExchange proxy, UriComponentsBuilder uri) - throws Exception { + public ResponseEntity proxyTypeless(ProxyExchange proxy, UriComponentsBuilder uri) { String path = proxy.path("/proxy/typeless"); return proxy.uri(home.toString() + path).get(); } @GetMapping("/proxy/missing/{id}") - public ResponseEntity proxyMissing(@PathVariable Integer id, ProxyExchange proxy) throws Exception { + public ResponseEntity proxyMissing(@PathVariable Integer id, ProxyExchange proxy) { return proxy.uri(home.toString() + "/missing/" + id).get(); } @GetMapping("/proxy") - public ResponseEntity proxyUri(ProxyExchange proxy) throws Exception { + public ResponseEntity proxyUri(ProxyExchange proxy) { return proxy.uri(home.toString() + "/foos").get(); } @PostMapping("/proxy/{id}") public ResponseEntity proxyBars(@PathVariable Integer id, @RequestBody Map body, - ProxyExchange> proxy) throws Exception { + ProxyExchange> proxy) { body.put("id", id); return proxy.uri(home.toString() + "/bars").body(Arrays.asList(body)).post(this::first); } @PostMapping("/proxy") - public ResponseEntity barsWithNoBody(ProxyExchange proxy) throws Exception { + public ResponseEntity barsWithNoBody(ProxyExchange proxy) { return proxy.uri(home.toString() + "/bars").post(); } @PostMapping("/proxy/entity") - public ResponseEntity explicitEntity(@RequestBody Foo foo, ProxyExchange proxy) throws Exception { + public ResponseEntity explicitEntity(@RequestBody Foo foo, ProxyExchange proxy) { return proxy.uri(home.toString() + "/bars").body(Arrays.asList(foo)).post(); } @PostMapping("/proxy/type") public ResponseEntity> explicitEntityWithType(@RequestBody Foo foo, - ProxyExchange> proxy) throws Exception { + ProxyExchange> proxy) { return proxy.uri(home.toString() + "/bars").body(Arrays.asList(foo)).post(); } @PostMapping("/proxy/single") - public ResponseEntity implicitEntity(@RequestBody Foo foo, ProxyExchange> proxy) - throws Exception { + public ResponseEntity implicitEntity(@RequestBody Foo foo, ProxyExchange> proxy) { return proxy.uri(home.toString() + "/bars").body(Arrays.asList(foo)).post(this::first); } @PostMapping("/proxy/converter") - public ResponseEntity implicitEntityWithConverter(@RequestBody Foo foo, ProxyExchange> proxy) - throws Exception { + public ResponseEntity implicitEntityWithConverter(@RequestBody Foo foo, + ProxyExchange> proxy) { return proxy.uri(home.toString() + "/bars").body(Arrays.asList(foo)) .post(response -> ResponseEntity.status(response.getStatusCode()).headers(response.getHeaders()) .body(response.getBody().iterator().next())); } @PostMapping("/proxy/no-body") - public ResponseEntity noBody(ProxyExchange proxy) throws Exception { + public ResponseEntity noBody(ProxyExchange proxy) { return proxy.uri(home.toString() + "/foos").post(); } @DeleteMapping("/proxy/{id}/no-body") - public ResponseEntity deleteWithoutBody(@PathVariable Integer id, ProxyExchange proxy) - throws Exception { + public ResponseEntity deleteWithoutBody(@PathVariable Integer id, ProxyExchange proxy) { return proxy.uri(home.toString() + "/foos/" + id + "/no-body").delete(); } @DeleteMapping("/proxy/{id}") public ResponseEntity deleteWithBody(@PathVariable Integer id, @RequestBody Foo foo, - ProxyExchange proxy) throws Exception { + ProxyExchange proxy) { return proxy.uri(home.toString() + "/foos/" + id).body(foo).delete(response -> ResponseEntity .status(response.getStatusCode()).headers(response.getHeaders()).body(response.getBody())); } @GetMapping("/forward/**") - public void forward(ProxyExchange proxy) throws Exception { + public void forward(ProxyExchange proxy) { String path = proxy.path("/forward"); if (path.startsWith("/special")) { proxy.header("X-Custom", "FOO"); @@ -406,7 +402,7 @@ public class ProductionConfigurationTests { } @PostMapping("/forward/**") - public void postForward(ProxyExchange proxy) throws Exception { + public void postForward(ProxyExchange proxy) { String path = proxy.path("/forward"); if (path.startsWith("/special")) { proxy.header("X-Custom", "FOO"); @@ -416,13 +412,14 @@ public class ProductionConfigurationTests { } @PostMapping("/forward/body/**") - public void postForwardBody(@RequestBody byte[] body, ProxyExchange proxy) throws Exception { + public void postForwardBody(@RequestBody byte[] body, ProxyExchange proxy) { String path = proxy.path("/forward/body"); proxy.body(body).forward(path); } + @SuppressWarnings("unused") @PostMapping("/forward/forget/**") - public void postForwardForgetBody(@RequestBody byte[] body, ProxyExchange proxy) throws Exception { + public void postForwardForgetBody(@RequestBody byte[] body, ProxyExchange proxy) { String path = proxy.path("/forward/forget"); proxy.forward(path); } diff --git a/spring-cloud-gateway-mvc/src/test/java/org/springframework/cloud/gateway/mvc/http/HttpComponentsClientHttpRequest.java b/spring-cloud-gateway-mvc/src/test/java/org/springframework/cloud/gateway/mvc/http/HttpComponentsClientHttpRequest.java index 24b2c3f3..0983fb62 100644 --- a/spring-cloud-gateway-mvc/src/test/java/org/springframework/cloud/gateway/mvc/http/HttpComponentsClientHttpRequest.java +++ b/spring-cloud-gateway-mvc/src/test/java/org/springframework/cloud/gateway/mvc/http/HttpComponentsClientHttpRequest.java @@ -58,6 +58,7 @@ final class HttpComponentsClientHttpRequest extends AbstractBufferingClientHttpR return HttpMethod.valueOf(httpRequest.getMethod()); } + @Deprecated @Override public String getMethodValue() { return httpRequest.getMethod(); diff --git a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/config/GatewayProperties.java b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/config/GatewayProperties.java index b0008371..13d44243 100644 --- a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/config/GatewayProperties.java +++ b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/config/GatewayProperties.java @@ -59,7 +59,7 @@ public class GatewayProperties { private List defaultFilters = new ArrayList<>(); private List streamingMediaTypes = Arrays.asList(MediaType.TEXT_EVENT_STREAM, - MediaType.APPLICATION_STREAM_JSON, new MediaType("application", "grpc"), + new MediaType("application", "stream+json"), new MediaType("application", "grpc"), new MediaType("application", "grpc+protobuf"), new MediaType("application", "grpc+json")); /** diff --git a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/LoadBalancerServiceInstanceCookieFilter.java b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/LoadBalancerServiceInstanceCookieFilter.java index 6f05c39f..4874a563 100644 --- a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/LoadBalancerServiceInstanceCookieFilter.java +++ b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/LoadBalancerServiceInstanceCookieFilter.java @@ -48,12 +48,7 @@ public class LoadBalancerServiceInstanceCookieFilter implements GlobalFilter, Or private ReactiveLoadBalancer.Factory loadBalancerClientFactory; - /** - * @deprecated in favour of - * {@link LoadBalancerServiceInstanceCookieFilter#LoadBalancerServiceInstanceCookieFilter(ReactiveLoadBalancer.Factory)} - */ - @Deprecated - public LoadBalancerServiceInstanceCookieFilter(LoadBalancerProperties loadBalancerProperties) { + LoadBalancerServiceInstanceCookieFilter(LoadBalancerProperties loadBalancerProperties) { this.loadBalancerProperties = loadBalancerProperties; } diff --git a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/NettyRoutingFilter.java b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/NettyRoutingFilter.java index d0f12acb..1243c1af 100644 --- a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/NettyRoutingFilter.java +++ b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/NettyRoutingFilter.java @@ -119,7 +119,7 @@ public class NettyRoutingFilter implements GlobalFilter, Ordered { ServerHttpRequest request = exchange.getRequest(); - final HttpMethod method = HttpMethod.valueOf(request.getMethodValue()); + final HttpMethod method = HttpMethod.valueOf(request.getMethod().name()); final String url = requestUrl.toASCIIString(); HttpHeaders filtered = filterRequest(getHeadersFilters(), exchange); diff --git a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/factory/SpringCloudCircuitBreakerFilterFactory.java b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/factory/SpringCloudCircuitBreakerFilterFactory.java index b6cb2eb8..406223a3 100644 --- a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/factory/SpringCloudCircuitBreakerFilterFactory.java +++ b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/factory/SpringCloudCircuitBreakerFilterFactory.java @@ -189,7 +189,7 @@ public abstract class SpringCloudCircuitBreakerFilterFactory } public String getId() { - if (StringUtils.isEmpty(name) && !StringUtils.isEmpty(routeId)) { + if (!StringUtils.hasText(name) && StringUtils.hasText(routeId)) { return routeId; } return name; diff --git a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/route/builder/PredicateSpec.java b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/route/builder/PredicateSpec.java index d41130c8..d88a7cc1 100644 --- a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/route/builder/PredicateSpec.java +++ b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/route/builder/PredicateSpec.java @@ -151,7 +151,7 @@ public class PredicateSpec extends UriSpec { */ public BooleanSpec method(String... methods) { return asyncPredicate(getBean(MethodRoutePredicateFactory.class).applyAsync(c -> { - HttpMethod[] httpMethods = stream(methods).map(HttpMethod::resolve).toArray(HttpMethod[]::new); + HttpMethod[] httpMethods = stream(methods).map(HttpMethod::valueOf).toArray(HttpMethod[]::new); c.setMethods(httpMethods); })); } diff --git a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/support/GatewayToStringStyler.java b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/support/GatewayToStringStyler.java index f016ec1e..1d47c454 100644 --- a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/support/GatewayToStringStyler.java +++ b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/support/GatewayToStringStyler.java @@ -24,6 +24,7 @@ import org.springframework.core.style.DefaultValueStyler; import org.springframework.core.style.ToStringCreator; import org.springframework.util.ClassUtils; +@SuppressWarnings("rawtypes") public class GatewayToStringStyler extends DefaultToStringStyler { private static final GatewayToStringStyler FILTER_INSTANCE = new GatewayToStringStyler(GatewayFilterFactory.class, diff --git a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/support/tagsprovider/GatewayHttpTagsProvider.java b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/support/tagsprovider/GatewayHttpTagsProvider.java index d416589d..20f2e57b 100644 --- a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/support/tagsprovider/GatewayHttpTagsProvider.java +++ b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/support/tagsprovider/GatewayHttpTagsProvider.java @@ -33,7 +33,7 @@ public class GatewayHttpTagsProvider implements GatewayTagsProvider { String status = "CUSTOM"; String httpStatusCodeStr = "NA"; - String httpMethod = exchange.getRequest().getMethodValue(); + String httpMethod = exchange.getRequest().getMethod().name(); // a non standard HTTPS status could be used. Let's be defensive here // it needs to be checked for first, otherwise the delegate response diff --git a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/cors/SimpleUrlHandlerCorsTests.java b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/cors/SimpleUrlHandlerCorsTests.java index 7a6427ec..784d6bae 100644 --- a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/cors/SimpleUrlHandlerCorsTests.java +++ b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/cors/SimpleUrlHandlerCorsTests.java @@ -16,7 +16,7 @@ package org.springframework.cloud.gateway.cors; -import java.util.Arrays; +import java.util.List; import org.junit.jupiter.api.Test; import reactor.core.publisher.Mono; @@ -31,9 +31,9 @@ import org.springframework.context.annotation.Import; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpMethod; import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; import org.springframework.test.annotation.DirtiesContext; import org.springframework.test.context.ActiveProfiles; -import org.springframework.web.reactive.function.client.ClientResponse; import static org.assertj.core.api.Assertions.assertThat; import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT; @@ -46,30 +46,29 @@ public class SimpleUrlHandlerCorsTests extends BaseWebClientTests { @Test public void testPreFlightCorsRequestNotHandledByGW() { - ClientResponse clientResponse = webClient.options().uri("/abc/123/function").header("Origin", "domain.com") - .header("Access-Control-Request-Method", "GET").exchange().block(); - HttpHeaders asHttpHeaders = clientResponse.headers().asHttpHeaders(); - Mono bodyToMono = clientResponse.bodyToMono(String.class); + ResponseEntity response = webClient.options().uri("/abc/123/function").header("Origin", "domain.com") + .header("Access-Control-Request-Method", "GET").retrieve().toEntity(String.class).block(); + HttpHeaders asHttpHeaders = response.getHeaders(); // pre-flight request shouldn't return the response body - assertThat(bodyToMono.block()).isNull(); + assertThat(response.getBody()).isNull(); assertThat(asHttpHeaders.getAccessControlAllowOrigin()) .as("Missing header value in response: " + HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN).isEqualTo("*"); assertThat(asHttpHeaders.getAccessControlAllowMethods()) .as("Missing header value in response: " + HttpHeaders.ACCESS_CONTROL_ALLOW_METHODS) - .isEqualTo(Arrays.asList(new HttpMethod[] { HttpMethod.GET })); - assertThat(clientResponse.statusCode()).as("Pre Flight call failed.").isEqualTo(HttpStatus.OK); + .isEqualTo(List.of(HttpMethod.GET)); + assertThat(response.getStatusCode()).as("Pre Flight call failed.").isEqualTo(HttpStatus.OK); } @Test public void testCorsRequestNotHandledByGW() { - ClientResponse clientResponse = webClient.get().uri("/abc/123/function").header("Origin", "domain.com") - .header(HttpHeaders.HOST, "www.path.org").exchange().block(); - HttpHeaders asHttpHeaders = clientResponse.headers().asHttpHeaders(); - Mono bodyToMono = clientResponse.bodyToMono(String.class); - assertThat(bodyToMono.block()).isNotNull(); + ResponseEntity responseEntity = webClient.get().uri("/abc/123/function").header("Origin", "domain.com") + .header(HttpHeaders.HOST, "www.path.org").retrieve().onStatus(HttpStatus::isError, t -> Mono.empty()) + .toEntity(String.class).block(); + HttpHeaders asHttpHeaders = responseEntity.getHeaders(); + assertThat(responseEntity.getBody()).isNotNull(); assertThat(asHttpHeaders.getAccessControlAllowOrigin()) .as("Missing header value in response: " + HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN).isEqualTo("*"); - assertThat(clientResponse.statusCode()).as("CORS request failed.").isEqualTo(HttpStatus.NOT_FOUND); + assertThat(responseEntity.getStatusCode()).as("CORS request failed.").isEqualTo(HttpStatus.NOT_FOUND); } @EnableAutoConfiguration diff --git a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/filter/ReactiveLoadBalancerClientFilterTests.java b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/filter/ReactiveLoadBalancerClientFilterTests.java index 6c08b199..334ca6fd 100644 --- a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/filter/ReactiveLoadBalancerClientFilterTests.java +++ b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/filter/ReactiveLoadBalancerClientFilterTests.java @@ -268,8 +268,7 @@ class ReactiveLoadBalancerClientFilterTests { ServiceInstanceListSuppliers.toProvider("service1"), "service1", -1); when(clientFactory.getInstance("service1", ReactorServiceInstanceLoadBalancer.class)).thenReturn(loadBalancer); properties.setUse404(true); - ReactiveLoadBalancerClientFilter filter = new ReactiveLoadBalancerClientFilter(clientFactory, properties, - loadBalancerProperties); + ReactiveLoadBalancerClientFilter filter = new ReactiveLoadBalancerClientFilter(clientFactory, properties); when(chain.filter(exchange)).thenReturn(Mono.empty()); try { filter.filter(exchange, chain).block(); @@ -442,8 +441,7 @@ class ReactiveLoadBalancerClientFilterTests { "service1", -1); when(clientFactory.getInstance("service1", ReactorServiceInstanceLoadBalancer.class)).thenReturn(loadBalancer); - ReactiveLoadBalancerClientFilter filter = new ReactiveLoadBalancerClientFilter(clientFactory, properties, - loadBalancerProperties); + ReactiveLoadBalancerClientFilter filter = new ReactiveLoadBalancerClientFilter(clientFactory, properties); filter.filter(exchange, chain).block(); return captor.getValue(); diff --git a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/filter/factory/CacheRequestBodyGatewayFilterFactoryTests.java b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/filter/factory/CacheRequestBodyGatewayFilterFactoryTests.java index 5e2f5d49..c17a027a 100644 --- a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/filter/factory/CacheRequestBodyGatewayFilterFactoryTests.java +++ b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/filter/factory/CacheRequestBodyGatewayFilterFactoryTests.java @@ -127,7 +127,7 @@ public class CacheRequestBodyGatewayFilterFactoryTests extends BaseWebClientTest private String bodyExcepted; AssertCachedRequestBodyGatewayFilter(String body) { - this.exceptNullBody = StringUtils.isEmpty(body); + this.exceptNullBody = !StringUtils.hasText(body); this.bodyExcepted = body; } diff --git a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/filter/factory/RetryGatewayFilterFactoryIntegrationTests.java b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/filter/factory/RetryGatewayFilterFactoryIntegrationTests.java index d2ac12e4..80fd18ea 100644 --- a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/filter/factory/RetryGatewayFilterFactoryIntegrationTests.java +++ b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/filter/factory/RetryGatewayFilterFactoryIntegrationTests.java @@ -188,6 +188,7 @@ public class RetryGatewayFilterFactoryIntegrationTests extends BaseWebClientTest } @Test + @SuppressWarnings("unchecked") public void toStringFormat() { RetryConfig config = new RetryConfig(); config.setRetries(4); diff --git a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/filter/factory/SecureHeadersGatewayFilterFactoryTests.java b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/filter/factory/SecureHeadersGatewayFilterFactoryTests.java index c2886f74..334febf6 100644 --- a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/filter/factory/SecureHeadersGatewayFilterFactoryTests.java +++ b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/filter/factory/SecureHeadersGatewayFilterFactoryTests.java @@ -28,6 +28,7 @@ import org.springframework.context.annotation.Import; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; import org.springframework.test.annotation.DirtiesContext; import org.springframework.web.reactive.function.client.ClientResponse; @@ -73,13 +74,13 @@ public class SecureHeadersGatewayFilterFactoryTests extends BaseWebClientTests { @Test public void addsSecureHeadersAfterResponseIsReceived() { - Mono result = webClient.patch().uri("/headers").header("Host", "www.secureheaders.org") - .contentType(MediaType.APPLICATION_JSON).bodyValue("{ \"X-Frame-Options\": \"sameorigin\" }") - .exchange(); + Mono> responseEntity = webClient.patch().uri("/headers") + .header("Host", "www.secureheaders.org").contentType(MediaType.APPLICATION_JSON) + .bodyValue("{ \"X-Frame-Options\": \"sameorigin\" }").retrieve().toEntity(String.class); - StepVerifier.create(result).consumeNextWith(response -> { - assertThat(response.statusCode()).isEqualTo(HttpStatus.OK); - assertThat(response.headers().header(X_FRAME_OPTIONS_HEADER)).containsOnly("sameorigin"); + StepVerifier.create(responseEntity).consumeNextWith(response -> { + assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK); + assertThat(response.getHeaders().get(X_FRAME_OPTIONS_HEADER)).containsOnly("sameorigin"); }).expectComplete().verify(DURATION); } diff --git a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/filter/factory/SpringCloudCircuitBreakerResilience4JFilterFactoryTests.java b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/filter/factory/SpringCloudCircuitBreakerResilience4JFilterFactoryTests.java index 8953a200..c0c7fb34 100644 --- a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/filter/factory/SpringCloudCircuitBreakerResilience4JFilterFactoryTests.java +++ b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/filter/factory/SpringCloudCircuitBreakerResilience4JFilterFactoryTests.java @@ -16,6 +16,8 @@ package org.springframework.cloud.gateway.filter.factory; +import io.github.resilience4j.circuitbreaker.CircuitBreakerRegistry; +import io.github.resilience4j.timelimiter.TimeLimiterRegistry; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; @@ -81,7 +83,9 @@ public class SpringCloudCircuitBreakerResilience4JFilterFactoryTests SpringCloudCircuitBreakerFilterFactory.Config config = new SpringCloudCircuitBreakerFilterFactory.Config() .setName("myname").setFallbackUri("forward:/myfallback"); GatewayFilter filter = new SpringCloudCircuitBreakerResilience4JFilterFactory( - new ReactiveResilience4JCircuitBreakerFactory(), null).apply(config); + new ReactiveResilience4JCircuitBreakerFactory(CircuitBreakerRegistry.ofDefaults(), + TimeLimiterRegistry.ofDefaults()), + null).apply(config); assertThat(filter.toString()).contains("myname").contains("forward:/myfallback"); } diff --git a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/test/websocket/WebSocketIntegrationTests.java b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/test/websocket/WebSocketIntegrationTests.java index 8c2e3461..afb61ff1 100644 --- a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/test/websocket/WebSocketIntegrationTests.java +++ b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/test/websocket/WebSocketIntegrationTests.java @@ -29,13 +29,11 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.condition.DisabledIfEnvironmentVariable; -import org.reactivestreams.Publisher; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; -import reactor.core.publisher.MonoProcessor; -import reactor.core.publisher.ReplayProcessor; import reactor.core.publisher.Sinks; import org.springframework.beans.factory.annotation.Value; @@ -59,6 +57,7 @@ import org.springframework.context.annotation.Import; import org.springframework.core.env.ConfigurableEnvironment; import org.springframework.core.env.Environment; import org.springframework.http.HttpHeaders; +import org.springframework.http.ResponseCookie; import org.springframework.http.server.reactive.HttpHandler; import org.springframework.util.StringUtils; import org.springframework.web.reactive.DispatcherHandler; @@ -76,6 +75,7 @@ import org.springframework.web.reactive.socket.server.WebSocketService; import org.springframework.web.reactive.socket.server.support.HandshakeWebSocketService; import org.springframework.web.reactive.socket.server.support.WebSocketHandlerAdapter; import org.springframework.web.reactive.socket.server.upgrade.ReactorNettyRequestUpgradeStrategy; +import org.springframework.web.server.WebFilter; import org.springframework.web.server.adapter.WebHttpHandlerBuilder; import static org.assertj.core.api.Assertions.assertThat; @@ -91,6 +91,8 @@ import static org.springframework.cloud.gateway.filter.WebsocketRoutingFilter.SE @DisabledIfEnvironmentVariable(named = "GITHUB_ACTIONS", matches = "true") public class WebSocketIntegrationTests { + private static final Duration TIMEOUT = Duration.ofMillis(5000); + private static final Log logger = LogFactory.getLog(WebSocketIntegrationTests.class); protected int serverPort; @@ -105,13 +107,6 @@ public class WebSocketIntegrationTests { private static final Sinks.One serverCloseStatusSink = Sinks.one(); - private static Mono doSend(WebSocketSession session, Publisher output) { - return session.send(output); - // workaround for suspected RxNetty WebSocket client issue - // https://github.com/ReactiveX/RxNetty/issues/560 - // return session.send(Mono.delay(Duration.ofMillis(100)).thenMany(output)); - } - @BeforeEach public void setup() throws Exception { this.client = new ReactorNettyWebSocketClient(); @@ -166,38 +161,29 @@ public class WebSocketIntegrationTests { public void echo() throws Exception { int count = 100; Flux input = Flux.range(1, count).map(index -> "msg-" + index); - ReplayProcessor output = ReplayProcessor.create(count); - - client.execute(getUrl("/echo"), session -> { - logger.debug("Starting to send messages"); - return session.send(input.doOnNext(s -> logger.debug("outbound " + s)).map(s -> session.textMessage(s))) - .thenMany(session.receive().take(count).map(WebSocketMessage::getPayloadAsText)) - .subscribeWith(output).doOnNext(s -> logger.debug("inbound " + s)).then() - .doOnSuccess(aVoid -> logger.debug("Done with success")) - .doOnError(ex -> logger.debug("Done with " + (ex != null ? ex.getMessage() : "error"))); - }).block(Duration.ofMillis(5000)); - - assertThat(output.collectList().block(Duration.ofMillis(5000))) - .isEqualTo(input.collectList().block(Duration.ofMillis(5000))); + AtomicReference> actualRef = new AtomicReference<>(); + this.client.execute(getUrl("/echo"), + session -> session.send(input.map(session::textMessage)) + .thenMany(session.receive().take(count).map(WebSocketMessage::getPayloadAsText)).collectList() + .doOnNext(actualRef::set).then()) + .block(TIMEOUT); + assertThat(actualRef.get()).isNotNull(); + assertThat(actualRef.get()).isEqualTo(input.collectList().block()); } @Test public void echoForHttp() throws Exception { int count = 100; Flux input = Flux.range(1, count).map(index -> "msg-" + index); - ReplayProcessor output = ReplayProcessor.create(count); - - client.execute(getHttpUrl("/echoForHttp"), session -> { + AtomicReference> actualRef = new AtomicReference<>(); + this.client.execute(getHttpUrl("/echoForHttp"), session -> { logger.debug("Starting to send messages"); - return session.send(input.doOnNext(s -> logger.debug("outbound " + s)).map(s -> session.textMessage(s))) - .thenMany(session.receive().take(count).map(WebSocketMessage::getPayloadAsText)) - .subscribeWith(output).doOnNext(s -> logger.debug("inbound " + s)).then() - .doOnSuccess(aVoid -> logger.debug("Done with success")) - .doOnError(ex -> logger.debug("Done with " + (ex != null ? ex.getMessage() : "error"))); - }).block(Duration.ofMillis(5000)); - - assertThat(output.collectList().block(Duration.ofMillis(5000))) - .isEqualTo(input.collectList().block(Duration.ofMillis(5000))); + return session.send(input.doOnNext(s -> logger.debug("outbound " + s)).map(session::textMessage)) + .thenMany(session.receive().take(count).map(WebSocketMessage::getPayloadAsText)).collectList() + .doOnNext(actualRef::set).then(); + }).block(TIMEOUT); + assertThat(actualRef.get()).isNotNull(); + assertThat(actualRef.get()).isEqualTo(input.collectList().block()); } @Test @@ -205,9 +191,9 @@ public class WebSocketIntegrationTests { String protocol = "echo-v1"; String protocol2 = "echo-v2"; AtomicReference infoRef = new AtomicReference<>(); - MonoProcessor output = MonoProcessor.create(); + AtomicReference protocolRef = new AtomicReference<>(); - client.execute(getUrl("/sub-protocol"), new WebSocketHandler() { + this.client.execute(getUrl("/sub-protocol"), new WebSocketHandler() { @Override public List getSubProtocols() { return Arrays.asList(protocol, protocol2); @@ -216,30 +202,29 @@ public class WebSocketIntegrationTests { @Override public Mono handle(WebSocketSession session) { infoRef.set(session.getHandshakeInfo()); - return session.receive().map(WebSocketMessage::getPayloadAsText).subscribeWith(output).then(); + return session.receive().map(WebSocketMessage::getPayloadAsText).doOnNext(protocolRef::set) + .doOnError(protocolRef::set).then(); } - }).block(Duration.ofMillis(5000)); + }).block(TIMEOUT); HandshakeInfo info = infoRef.get(); assertThat(info.getHeaders().getFirst("Upgrade")).isEqualToIgnoringCase("websocket"); - assertThat(info.getHeaders().getFirst("Sec-WebSocket-Protocol")).isEqualTo(protocol); assertThat(info.getSubProtocol()).as("Wrong protocol accepted").isEqualTo(protocol); - assertThat(output.block(Duration.ofSeconds(5))).as("Wrong protocol detected on the server side") - .isEqualTo(protocol); + assertThat(protocolRef.get()).as("Wrong protocol detected on the server side").isEqualTo(protocol); } @Test public void customHeader() throws Exception { HttpHeaders headers = new HttpHeaders(); headers.add("my-header", "my-value"); - MonoProcessor output = MonoProcessor.create(); + AtomicReference headerRef = new AtomicReference<>(); - client.execute(getUrl("/custom-header"), headers, - session -> session.receive().map(WebSocketMessage::getPayloadAsText).subscribeWith(output).then()) - .block(Duration.ofMillis(5000)); + this.client.execute(getUrl("/custom-header"), headers, session -> session.receive() + .map(WebSocketMessage::getPayloadAsText).doOnNext(headerRef::set).doOnError(headerRef::set).then()) + .block(TIMEOUT); - assertThat(output.block(Duration.ofMillis(5000))).isEqualTo("my-header:my-value"); + assertThat(headerRef.get()).isEqualTo("my-header:my-value"); } @Test @@ -264,6 +249,20 @@ public class WebSocketIntegrationTests { .isEqualTo(CloseStatus.create(4999, "client-close")); } + @Disabled + @Test + void cookie() throws Exception { + AtomicReference cookie = new AtomicReference<>(); + AtomicReference receivedCookieRef = new AtomicReference<>(); + this.client.execute(getUrl("/cookie"), session -> { + cookie.set(session.getHandshakeInfo().getHeaders().getFirst("Set-Cookie")); + return session.receive().map(WebSocketMessage::getPayloadAsText).doOnNext(receivedCookieRef::set) + .doOnError(receivedCookieRef::set).then(); + }).block(TIMEOUT); + assertThat(receivedCookieRef.get()).isEqualTo("cookie"); + assertThat(cookie.get()).isEqualTo("project=spring"); + } + @Configuration(proxyBeanMethods = false) static class WebSocketTestConfig { @@ -295,12 +294,23 @@ public class WebSocketIntegrationTests { map.put("/custom-header", new CustomHeaderHandler()); map.put("/server-close", new ServerClosingHandler()); map.put("/client-close", new ClientClosingHandler()); + map.put("/cookie", new CookieHandler()); SimpleUrlHandlerMapping mapping = new SimpleUrlHandlerMapping(); mapping.setUrlMap(map); return mapping; } + @Bean + public WebFilter cookieWebFilter() { + return (exchange, chain) -> { + if (exchange.getRequest().getPath().value().startsWith("/cookie")) { + exchange.getResponse().addCookie(ResponseCookie.from("project", "spring").build()); + } + return chain.filter(exchange); + }; + } + } private static class EchoWebSocketHandler implements WebSocketHandler { @@ -328,8 +338,8 @@ public class WebSocketIntegrationTests { } List protocols = session.getHandshakeInfo().getHeaders().get(SEC_WEBSOCKET_PROTOCOL); assertThat(protocols).contains("echo-v1,echo-v2"); - WebSocketMessage message = session.textMessage(protocol); - return doSend(session, Mono.just(message)); + WebSocketMessage message = session.textMessage(protocol != null ? protocol : "none"); + return session.send(Mono.just(message)); } } @@ -344,7 +354,7 @@ public class WebSocketIntegrationTests { } String payload = "my-header:" + headers.getFirst("my-header"); WebSocketMessage message = session.textMessage(payload); - return doSend(session, Mono.just(message)); + return session.send(Mono.just(message)); } } @@ -367,6 +377,16 @@ public class WebSocketIntegrationTests { } + private static class CookieHandler implements WebSocketHandler { + + @Override + public Mono handle(WebSocketSession session) { + WebSocketMessage message = session.textMessage("cookie"); + return session.send(Mono.just(message)); + } + + } + @Configuration(proxyBeanMethods = false) @EnableAutoConfiguration @Import(PermitAllSecurityConfiguration.class) diff --git a/spring-cloud-gateway-webflux/src/main/java/org/springframework/cloud/gateway/webflux/ProxyExchange.java b/spring-cloud-gateway-webflux/src/main/java/org/springframework/cloud/gateway/webflux/ProxyExchange.java index 5fc24d64..788d53d5 100644 --- a/spring-cloud-gateway-webflux/src/main/java/org/springframework/cloud/gateway/webflux/ProxyExchange.java +++ b/spring-cloud-gateway-webflux/src/main/java/org/springframework/cloud/gateway/webflux/ProxyExchange.java @@ -33,6 +33,7 @@ import org.springframework.core.ParameterizedTypeReference; import org.springframework.core.io.buffer.DataBuffer; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpMethod; +import org.springframework.http.HttpStatus; import org.springframework.http.RequestEntity; import org.springframework.http.RequestEntity.BodyBuilder; import org.springframework.http.ResponseEntity; @@ -43,7 +44,6 @@ import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.reactive.BindingContext; import org.springframework.web.reactive.function.BodyInserters; -import org.springframework.web.reactive.function.client.ClientResponse; import org.springframework.web.reactive.function.client.WebClient; import org.springframework.web.reactive.function.client.WebClient.RequestBodySpec; import org.springframework.web.server.ServerWebExchange; @@ -360,25 +360,26 @@ public class ProxyExchange { Type type = this.responseType; RequestBodySpec builder = rest.method(requestEntity.getMethod()).uri(requestEntity.getUrl()) .headers(headers -> addHeaders(headers, requestEntity.getHeaders())); - Mono result; + WebClient.ResponseSpec result; if (requestEntity.getBody() instanceof Publisher) { @SuppressWarnings("unchecked") Publisher publisher = (Publisher) requestEntity.getBody(); - result = builder.body(publisher, Object.class).exchange(); + result = builder.body(publisher, Object.class).retrieve(); } else if (requestEntity.getBody() != null) { - result = builder.body(BodyInserters.fromValue(requestEntity.getBody())).exchange(); + result = builder.body(BodyInserters.fromValue(requestEntity.getBody())).retrieve(); } else { if (hasBody) { result = builder.headers(headers -> addHeaders(headers, exchange.getRequest().getHeaders())) - .body(exchange.getRequest().getBody(), DataBuffer.class).exchange(); + .body(exchange.getRequest().getBody(), DataBuffer.class).retrieve(); } else { - result = builder.headers(headers -> addHeaders(headers, exchange.getRequest().getHeaders())).exchange(); + result = builder.headers(headers -> addHeaders(headers, exchange.getRequest().getHeaders())).retrieve(); } } - return result.flatMap(response -> response.toEntity(ParameterizedTypeReference.forType(type))); + return result.onStatus(HttpStatus::isError, t -> Mono.empty()) + .toEntity(ParameterizedTypeReference.forType(type)); } private void addHeaders(HttpHeaders headers, HttpHeaders toAdd) { @@ -436,7 +437,7 @@ public class ProxyExchange { } private String forwarded(URI uri, String hostHeader) { - if (!StringUtils.isEmpty(hostHeader)) { + if (StringUtils.hasText(hostHeader)) { return "host=" + hostHeader; } if ("http".equals(uri.getScheme())) { diff --git a/spring-cloud-gateway-webflux/src/test/java/org/springframework/cloud/gateway/webflux/ProductionConfigurationTests.java b/spring-cloud-gateway-webflux/src/test/java/org/springframework/cloud/gateway/webflux/ProductionConfigurationTests.java index b2351a76..04316699 100644 --- a/spring-cloud-gateway-webflux/src/test/java/org/springframework/cloud/gateway/webflux/ProductionConfigurationTests.java +++ b/spring-cloud-gateway-webflux/src/test/java/org/springframework/cloud/gateway/webflux/ProductionConfigurationTests.java @@ -238,7 +238,7 @@ public class ProductionConfigurationTests { ResponseEntity> deleteResponse = rest.exchange("/proxy/{id}", HttpMethod.DELETE, new HttpEntity(foo), returnType, Collections.singletonMap("id", "123")); assertThat(deleteResponse.getStatusCode()).isEqualTo(HttpStatus.OK); - assertThat(deleteResponse.getBody().get("deleted")).isEqualToComparingFieldByField(foo); + assertThat(deleteResponse.getBody().get("deleted")).usingRecursiveComparison().isEqualTo(foo); } @SpringBootApplication