Add the ability to provide a default ZuulFallbackProvider. Fixes #1506
This commit is contained in:
@@ -1755,6 +1755,56 @@ zuul:
|
||||
customers: /customers/**
|
||||
----
|
||||
|
||||
If you would like to provide a default fallback for all routes than you can create a bean of
|
||||
type `ZuulFallbackProvider` and have the `getRoute` method return `*` or `null`.
|
||||
|
||||
[source,java]
|
||||
----
|
||||
class MyFallbackProvider implements ZuulFallbackProvider {
|
||||
@Override
|
||||
public String getRoute() {
|
||||
return "*";
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClientHttpResponse fallbackResponse() {
|
||||
return new ClientHttpResponse() {
|
||||
@Override
|
||||
public HttpStatus getStatusCode() throws IOException {
|
||||
return HttpStatus.OK;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getRawStatusCode() throws IOException {
|
||||
return 200;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getStatusText() throws IOException {
|
||||
return "OK";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputStream getBody() throws IOException {
|
||||
return new ByteArrayInputStream("fallback".getBytes());
|
||||
}
|
||||
|
||||
@Override
|
||||
public HttpHeaders getHeaders() {
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.setContentType(MediaType.APPLICATION_JSON);
|
||||
return headers;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
----
|
||||
|
||||
[[zuul-developer-guide]]
|
||||
=== Zuul Developer Guide
|
||||
|
||||
|
||||
@@ -30,15 +30,25 @@ import org.springframework.cloud.netflix.zuul.filters.route.ZuulFallbackProvider
|
||||
public abstract class AbstractRibbonCommandFactory implements RibbonCommandFactory {
|
||||
|
||||
private Map<String, ZuulFallbackProvider> fallbackProviderCache;
|
||||
private ZuulFallbackProvider defaultFallbackProvider = null;
|
||||
|
||||
public AbstractRibbonCommandFactory(Set<ZuulFallbackProvider> fallbackProviders){
|
||||
this.fallbackProviderCache = new HashMap<>();
|
||||
for(ZuulFallbackProvider provider : fallbackProviders) {
|
||||
fallbackProviderCache.put(provider.getRoute(), provider);
|
||||
String route = provider.getRoute();
|
||||
if("*".equals(route) || route == null) {
|
||||
defaultFallbackProvider = provider;
|
||||
} else {
|
||||
fallbackProviderCache.put(route, provider);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected ZuulFallbackProvider getFallbackProvider(String route) {
|
||||
return fallbackProviderCache.get(route);
|
||||
ZuulFallbackProvider provider = fallbackProviderCache.get(route);
|
||||
if(provider == null) {
|
||||
provider = defaultFallbackProvider;
|
||||
}
|
||||
return provider;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ import static org.springframework.boot.test.context.SpringBootTest.WebEnvironmen
|
||||
* @author Ryan Baxter
|
||||
*/
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest(classes = HttpClientRibbonCommandIntegrationTests.TestConfig.class, webEnvironment = RANDOM_PORT,
|
||||
@SpringBootTest(classes = RibbonCommandFallbackTests.TestConfig.class, webEnvironment = RANDOM_PORT,
|
||||
properties = {
|
||||
"zuul.routes.simple: /simple/**", "zuul.routes.another: /another/twolevel/**",
|
||||
"ribbon.ReadTimeout: 1"})
|
||||
|
||||
@@ -31,7 +31,7 @@ import com.netflix.zuul.context.RequestContext;
|
||||
* @author Ryan Baxter
|
||||
*/
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@SpringBootTest(classes = OkHttpRibbonCommandIntegrationTests.TestConfig.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, value = {
|
||||
@SpringBootTest(classes = RibbonCommandFallbackTests.TestConfig.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, value = {
|
||||
"zuul.routes.simple: /simple/**", "zuul.routes.another: /another/twolevel/**",
|
||||
"ribbon.ReadTimeout: 1"})
|
||||
@DirtiesContext
|
||||
|
||||
@@ -31,7 +31,7 @@ import com.netflix.zuul.context.RequestContext;
|
||||
* @author Ryan Baxter
|
||||
*/
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@SpringBootTest(classes = RestClientRibbonCommandIntegrationTests.TestConfig.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, value = {
|
||||
@SpringBootTest(classes = RibbonCommandFallbackTests.TestConfig.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, value = {
|
||||
"zuul.routes.simple: /simple/**", "zuul.routes.another: /another/twolevel/**",
|
||||
"ribbon.ReadTimeout: 1"})
|
||||
@DirtiesContext
|
||||
|
||||
@@ -18,13 +18,35 @@
|
||||
|
||||
package org.springframework.cloud.netflix.zuul.filters.route.support;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Collections;
|
||||
import java.util.Set;
|
||||
import org.junit.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.web.ErrorAttributes;
|
||||
import org.springframework.boot.context.embedded.LocalServerPort;
|
||||
import org.springframework.boot.test.web.client.TestRestTemplate;
|
||||
import org.springframework.cloud.netflix.ribbon.RibbonClient;
|
||||
import org.springframework.cloud.netflix.ribbon.RibbonClients;
|
||||
import org.springframework.cloud.netflix.ribbon.SpringClientFactory;
|
||||
import org.springframework.cloud.netflix.zuul.EnableZuulProxy;
|
||||
import org.springframework.cloud.netflix.zuul.filters.ZuulProperties;
|
||||
import org.springframework.cloud.netflix.zuul.filters.route.RibbonCommandFactory;
|
||||
import org.springframework.cloud.netflix.zuul.filters.route.ZuulFallbackProvider;
|
||||
import org.springframework.cloud.netflix.zuul.filters.route.apache.HttpClientRibbonCommandFactory;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.http.HttpEntity;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.http.client.ClientHttpResponse;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
@@ -47,11 +69,90 @@ public abstract class RibbonCommandFallbackTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void noFallback() {
|
||||
public void defaultFallback() {
|
||||
String uri = "/another/twolevel/slow";
|
||||
ResponseEntity<String> result = new TestRestTemplate().exchange(
|
||||
"http://localhost:" + this.port + uri, HttpMethod.GET,
|
||||
new HttpEntity<>((Void) null), String.class);
|
||||
assertEquals(HttpStatus.INTERNAL_SERVER_ERROR, result.getStatusCode());
|
||||
assertEquals(HttpStatus.OK, result.getStatusCode());
|
||||
assertEquals("default fallback", result.getBody());
|
||||
}
|
||||
|
||||
// Don't use @SpringBootApplication because we don't want to component scan
|
||||
@Configuration
|
||||
@EnableAutoConfiguration
|
||||
@RestController
|
||||
@EnableZuulProxy
|
||||
@RibbonClients({
|
||||
@RibbonClient(name = "simple", configuration = ZuulProxyTestBase.SimpleRibbonClientConfiguration.class),
|
||||
@RibbonClient(name = "another", configuration = ZuulProxyTestBase.AnotherRibbonClientConfiguration.class)})
|
||||
public static class TestConfig extends ZuulProxyTestBase.AbstractZuulProxyApplication {
|
||||
|
||||
@Autowired(required = false)
|
||||
private Set<ZuulFallbackProvider> zuulFallbackProviders = Collections.emptySet();
|
||||
|
||||
|
||||
@Bean
|
||||
public RibbonCommandFactory<?> ribbonCommandFactory(
|
||||
final SpringClientFactory clientFactory) {
|
||||
return new HttpClientRibbonCommandFactory(clientFactory, new ZuulProperties(),
|
||||
zuulFallbackProviders);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public ZuulProxyTestBase.MyErrorController myErrorController(
|
||||
ErrorAttributes errorAttributes) {
|
||||
return new ZuulProxyTestBase.MyErrorController(errorAttributes);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public ZuulFallbackProvider defaultFallbackProvider() {
|
||||
return new DefaultFallbackProvider();
|
||||
}
|
||||
}
|
||||
|
||||
public static class DefaultFallbackProvider implements ZuulFallbackProvider {
|
||||
|
||||
@Override
|
||||
public String getRoute() {
|
||||
return "*";
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClientHttpResponse fallbackResponse() {
|
||||
return new ClientHttpResponse() {
|
||||
@Override
|
||||
public HttpStatus getStatusCode() throws IOException {
|
||||
return HttpStatus.OK;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getRawStatusCode() throws IOException {
|
||||
return 200;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getStatusText() throws IOException {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputStream getBody() throws IOException {
|
||||
return new ByteArrayInputStream("default fallback".getBytes());
|
||||
}
|
||||
|
||||
@Override
|
||||
public HttpHeaders getHeaders() {
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.setContentType(MediaType.TEXT_HTML);
|
||||
return headers;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user