diff --git a/spring-cloud-gateway-core/src/main/java/org/springframework/cloud/gateway/config/GatewayNoLoadBalancerClientAutoConfiguration.java b/spring-cloud-gateway-core/src/main/java/org/springframework/cloud/gateway/config/GatewayNoLoadBalancerClientAutoConfiguration.java index ac094168..f91b374c 100644 --- a/spring-cloud-gateway-core/src/main/java/org/springframework/cloud/gateway/config/GatewayNoLoadBalancerClientAutoConfiguration.java +++ b/spring-cloud-gateway-core/src/main/java/org/springframework/cloud/gateway/config/GatewayNoLoadBalancerClientAutoConfiguration.java @@ -24,6 +24,7 @@ import reactor.core.publisher.Mono; import org.springframework.boot.autoconfigure.AutoConfigureAfter; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass; +import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.cloud.client.loadbalancer.LoadBalancerClient; import org.springframework.cloud.gateway.filter.GatewayFilterChain; import org.springframework.cloud.gateway.filter.GlobalFilter; @@ -44,17 +45,24 @@ import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.G @Configuration @ConditionalOnMissingClass("org.springframework.cloud.netflix.ribbon.RibbonAutoConfiguration") @ConditionalOnMissingBean(LoadBalancerClient.class) +@EnableConfigurationProperties(LoadBalancerProperties.class) @AutoConfigureAfter(GatewayLoadBalancerClientAutoConfiguration.class) public class GatewayNoLoadBalancerClientAutoConfiguration { @Bean @ConditionalOnMissingBean(LoadBalancerClientFilter.class) - public NoLoadBalancerClientFilter noLoadBalancerClientFilter() { - return new NoLoadBalancerClientFilter(); - } + public NoLoadBalancerClientFilter noLoadBalancerClientFilter(LoadBalancerProperties properties) { + return new NoLoadBalancerClientFilter(properties.isUse404()); + } protected static class NoLoadBalancerClientFilter implements GlobalFilter, Ordered { + private final boolean use404; + + public NoLoadBalancerClientFilter(boolean use404) { + this.use404 = use404; + } + @Override public int getOrder() { return LOAD_BALANCER_CLIENT_FILTER_ORDER; @@ -69,7 +77,7 @@ public class GatewayNoLoadBalancerClientAutoConfiguration { return chain.filter(exchange); } - throw new NotFoundException("Unable to find instance for " + url.getHost()); + throw NotFoundException.create(use404, "Unable to find instance for " + url.getHost()); } } } diff --git a/spring-cloud-gateway-core/src/main/java/org/springframework/cloud/gateway/filter/LoadBalancerClientFilter.java b/spring-cloud-gateway-core/src/main/java/org/springframework/cloud/gateway/filter/LoadBalancerClientFilter.java index 3c3a1af4..fac7ed24 100644 --- a/spring-cloud-gateway-core/src/main/java/org/springframework/cloud/gateway/filter/LoadBalancerClientFilter.java +++ b/spring-cloud-gateway-core/src/main/java/org/springframework/cloud/gateway/filter/LoadBalancerClientFilter.java @@ -22,21 +22,18 @@ import java.util.Map; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import reactor.core.publisher.Mono; + import org.springframework.cloud.client.ServiceInstance; import org.springframework.cloud.client.loadbalancer.LoadBalancerClient; import org.springframework.cloud.gateway.config.LoadBalancerProperties; -import org.springframework.cloud.gateway.discovery.DiscoveryLocatorProperties; import org.springframework.cloud.gateway.support.NotFoundException; import org.springframework.core.Ordered; -import org.springframework.web.bind.annotation.ResponseStatus; import org.springframework.web.server.ServerWebExchange; import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR; import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.GATEWAY_SCHEME_PREFIX_ATTR; import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.addOriginalRequestUrl; -import static org.springframework.http.HttpStatus.NOT_FOUND; - -import reactor.core.publisher.Mono; /** * @author Spencer Gibb @@ -77,11 +74,7 @@ public class LoadBalancerClientFilter implements GlobalFilter, Ordered { final ServiceInstance instance = choose(exchange); if (instance == null) { - String msg = "Unable to find instance for " + url.getHost(); - if(properties.isUse404()) { - throw new FourOFourNotFoundException(msg); - } - throw new NotFoundException(msg); + throw NotFoundException.create(properties.isUse404(), "Unable to find instance for " + url.getHost()); } URI uri = exchange.getRequest().getURI(); @@ -103,12 +96,6 @@ public class LoadBalancerClientFilter implements GlobalFilter, Ordered { protected ServiceInstance choose(ServerWebExchange exchange) { return loadBalancer.choose(((URI) exchange.getAttribute(GATEWAY_REQUEST_URL_ATTR)).getHost()); } - @ResponseStatus(value = NOT_FOUND, reason = "The service was not found.") - static class FourOFourNotFoundException extends RuntimeException { - public FourOFourNotFoundException(String msg) { - super(msg); - } - } class DelegatingServiceInstance implements ServiceInstance { final ServiceInstance delegate; diff --git a/spring-cloud-gateway-core/src/main/java/org/springframework/cloud/gateway/support/NotFoundException.java b/spring-cloud-gateway-core/src/main/java/org/springframework/cloud/gateway/support/NotFoundException.java index 267193b6..0486b4d1 100644 --- a/spring-cloud-gateway-core/src/main/java/org/springframework/cloud/gateway/support/NotFoundException.java +++ b/spring-cloud-gateway-core/src/main/java/org/springframework/cloud/gateway/support/NotFoundException.java @@ -17,20 +17,37 @@ package org.springframework.cloud.gateway.support; -import org.springframework.web.bind.annotation.ResponseStatus; - -import static org.springframework.http.HttpStatus.SERVICE_UNAVAILABLE; +import org.springframework.http.HttpStatus; +import org.springframework.web.server.ResponseStatusException; /** * @author Spencer Gibb */ -@ResponseStatus(value = SERVICE_UNAVAILABLE, reason = "The service or item was not found.") -public class NotFoundException extends RuntimeException { +public class NotFoundException extends ResponseStatusException { public NotFoundException(String message) { - super(message); + this(HttpStatus.SERVICE_UNAVAILABLE, message); } public NotFoundException(String message, Throwable cause) { - super(message, cause); + this(HttpStatus.SERVICE_UNAVAILABLE, message, cause); } + + private NotFoundException(HttpStatus httpStatus, String message) { + super(httpStatus, message); + } + + private NotFoundException(HttpStatus httpStatus, String message, Throwable cause) { + super(httpStatus, message, cause); + } + + public static NotFoundException create(boolean with404, String message) { + HttpStatus httpStatus = with404? HttpStatus.NOT_FOUND: HttpStatus.SERVICE_UNAVAILABLE; + return new NotFoundException(httpStatus, message); + } + + public static NotFoundException create(boolean with404, String message, Throwable cause) { + HttpStatus httpStatus = with404? HttpStatus.NOT_FOUND: HttpStatus.SERVICE_UNAVAILABLE; + return new NotFoundException(httpStatus, message, cause); + } + } diff --git a/spring-cloud-gateway-core/src/test/java/org/springframework/cloud/gateway/filter/LoadBalancerClientFilterTests.java b/spring-cloud-gateway-core/src/test/java/org/springframework/cloud/gateway/filter/LoadBalancerClientFilterTests.java index 5bf6cc88..8c7dadff 100644 --- a/spring-cloud-gateway-core/src/test/java/org/springframework/cloud/gateway/filter/LoadBalancerClientFilterTests.java +++ b/spring-cloud-gateway-core/src/test/java/org/springframework/cloud/gateway/filter/LoadBalancerClientFilterTests.java @@ -9,19 +9,20 @@ import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; -import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.junit.MockitoJUnitRunner; +import reactor.core.publisher.Mono; + import org.springframework.cloud.client.DefaultServiceInstance; import org.springframework.cloud.client.ServiceInstance; import org.springframework.cloud.client.loadbalancer.LoadBalancerClient; import org.springframework.cloud.gateway.config.LoadBalancerProperties; -import org.springframework.cloud.gateway.discovery.DiscoveryLocatorProperties; import org.springframework.cloud.gateway.support.NotFoundException; import org.springframework.cloud.netflix.ribbon.RibbonLoadBalancerClient; import org.springframework.cloud.netflix.ribbon.RibbonLoadBalancerContext; import org.springframework.cloud.netflix.ribbon.SpringClientFactory; import org.springframework.http.HttpMethod; +import org.springframework.http.HttpStatus; import org.springframework.mock.http.server.reactive.MockServerHttpRequest; import org.springframework.mock.web.server.MockServerWebExchange; import org.springframework.util.StringUtils; @@ -39,8 +40,6 @@ import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.G import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR; import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.GATEWAY_SCHEME_PREFIX_ATTR; -import reactor.core.publisher.Mono; - /** * @author Spencer Gibb * @author Tim Ysewyn @@ -88,20 +87,32 @@ public class LoadBalancerClientFilterTests { verifyZeroInteractions(loadBalancerClient); } - @Test(expected = NotFoundException.class) + @Test public void shouldThrowExceptionWhenNoServiceInstanceIsFound() { URI uri = UriComponentsBuilder.fromUriString("lb://myservice").build().toUri(); exchange.getAttributes().put(GATEWAY_REQUEST_URL_ATTR, uri); - loadBalancerClientFilter.filter(exchange, chain); + try { + loadBalancerClientFilter.filter(exchange, chain); + } catch (NotFoundException e) { + assertThat(e.getStatus()).isEqualTo(HttpStatus.SERVICE_UNAVAILABLE); + } catch (Exception e) { + throw e; + } } - @Test(expected = LoadBalancerClientFilter.FourOFourNotFoundException.class) + @Test public void shouldThrow4O4ExceptionWhenNoServiceInstanceIsFound() { URI uri = UriComponentsBuilder.fromUriString("lb://myservice").build().toUri(); exchange.getAttributes().put(GATEWAY_REQUEST_URL_ATTR, uri); properties.setUse404(true); - loadBalancerClientFilter.filter(exchange, chain); + try { + loadBalancerClientFilter.filter(exchange, chain); + } catch (NotFoundException e) { + assertThat(e.getStatus()).isEqualTo(HttpStatus.NOT_FOUND); + } catch (Exception e) { + throw e; + } } @Test