Fallback for Zuul Route – Zuul路线的回落

最后修改: 2019年 10月 20日

中文/混合/英文(键盘快捷键:t)

1. Overview

1.概述

Zuul is an edge service (or API gateway) from Netflix that provides dynamic routing, monitoring, resiliency, and security.

Zuul是Netflix提供的边缘服务(或API网关),可提供动态路由、监控、弹性和安全。

In this tutorial, we’ll look at how to configure Zuul routes with fallbacks.

在本教程中,我们将研究如何配置带有回退功能的Zuul路由

2. Initial Setup

2.初始设置

To begin with, we’ll first set up two Spring Boot applications. In the first application, we’ll create a simple REST service. Whereas, in the second application, we’ll use the Zuul proxy to create a route for the REST service of the first application.

首先,我们将建立两个Spring Boot应用程序。在第一个应用程序中,我们将创建一个简单的REST服务。而在第二个应用程序中,我们将使用Zuul代理,为第一个应用程序的REST服务创建一个路由。

2.1. A Simple REST Service

2.1.一个简单的REST服务

Let’s say our application needs to display today’s weather information to the user. So, we’ll create a Spring Boot-based weather service application using the spring-boot-starter-web starter:

假设我们的应用程序需要向用户显示今天的天气信息。因此,我们将使用spring-boot-starter-web启动器创建一个基于Spring Boot的天气服务应用程序。

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

Now, we’ll create a controller for our weather service:

现在,我们将为我们的天气服务创建一个控制器。

@RestController
@RequestMapping("/weather")
public class WeatherController {

    @GetMapping("/today")
    public String getMessage() {
        return "It's a bright sunny day today!";
    }

}

Now, let’s run the weather service and check the weather service API:

现在,让我们运行天气服务并检查天气服务API。

$ curl -s localhost:8080/weather/today
It's a bright sunny day today!

2.2. The API Gateway Application

2.2.API网关的应用

Let’s now create our second Spring Boot application, the API Gateway. In this application, we’ll create a Zuul route for our weather service.

现在让我们来创建第二个Spring Boot应用程序,即API网关。在这个应用程序中,我们将为我们的天气服务创建一个Zuul路由。

And since both our weather service and Zuul will want to use 8080 by default, we’ll configure it to run on a different port, 7070.

由于我们的天气服务和Zuul都希望在默认情况下使用8080,我们将配置它运行在一个不同的端口,即7070。

So, let’s first add the spring-cloud-starter-netflix-zuul in pom.xml:

因此,让我们首先在pom.xml中添加spring-cloud-starter-netflix-zuul

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-zuul</artifactId>
</dependency>

Next, we’ll add the @EnableZuulProxy annotation to our API Gateway application class:

接下来,我们将把@EnableZuulProxy注解添加到我们的API网关应用类。

@SpringBootApplication
@EnableZuulProxy
public class ApiGatewayApplication {

    public static void main(String[] args) {
        SpringApplication.run(ApiGatewayApplication.class, args);
    }

}

Finally, we’ll configure the Zuul route, using Ribbon, for our weather service API in application.yml:

最后,我们将在application.yml中为我们的天气服务API配置Zuul路由,使用Ribbon。

spring:
   application:
      name: api-gateway
server:
   port: 7070
  
zuul:
   igoredServices: '*'
   routes:
      weather-service:
         path: /weather/**
         serviceId: weather-service
         strip-prefix: false

ribbon:
   eureka:
      enabled: false

weather-service:
   ribbon:
      listOfServers: localhost:8080

2.3. Testing the Zuul Route

2.3.测试Zuul路线

At this point, both Spring Boot applications are set up to expose the weather service API using Zuul proxy.

在这一点上,两个Spring Boot应用程序都被设置为使用Zuul代理暴露天气服务API。

So, let’s run both the applications and check the weather service API via Zuul:

因此,让我们运行这两个应用程序并通过Zuul检查天气服务API。

$ curl -s localhost:7070/weather/today
It's a bright sunny day today!

2.4. Testing the Zuul Route Failure Without Fallback

2.4.测试没有回落的Zuul路由故障

Now, let’s stop the weather service application and check the weather service via Zuul again. As a result, we’ll see an error message in the response:

现在,让我们停止天气服务应用程序,再次通过Zuul检查天气服务。结果是,我们会在响应中看到一条错误信息。

$ curl -s localhost:7070/weather/today
{"timestamp":"2019-10-08T12:42:09.479+0000","status":500,
"error":"Internal Server Error","message":"GENERAL"}

Obviously, this is not the response the user would like to see. So, one of the ways we can take care of this is to create a fallback for the weather service Zuul route.

很明显,这不是用户希望看到的反应。因此,我们可以照顾到这一点的方法之一是为天气服务Zuul路线创建一个回退。

3. Zuul Fallback for a Route

3.路线的Zuul Fallback

The Zuul proxy uses Ribbon for load balancing and the requests execute in the Hystrix command. As a result, failures in the Zuul route appear in a Hystrix matrix.

Zuul代理使用Ribbon进行负载平衡,请求在Hystrix命令中执行。因此,Zuul路由中的故障出现在Hystrix矩阵中

Therefore, to create a custom fallback for a Zuul route, we’ll create a bean of type FallbackProvider.

因此,为了给Zuul路由创建一个自定义回退,我们将创建一个FallbackProvider类型的bean。

3.1. The WeatherServiceFallback Class

3.1.WeatherServiceFallback

In this example, we want to return a message from the fallback response instead of the default error message that we saw earlier. So, let’s create a simple implementation of FallbackProvider for the weather service route:

在这个例子中,我们想从回退响应中返回一条信息,而不是我们之前看到的默认错误信息。因此,让我们为天气服务路线创建一个简单的FallbackProvider的实现。

@Component
class WeatherServiceFallback implements FallbackProvider {

    private static final String DEFAULT_MESSAGE = "Weather information is not available.";

    @Override
    public String getRoute() {
        return "weather-service";
    }

    @Override
    public ClientHttpResponse fallbackResponse(String route, Throwable cause) {
        if (cause instanceof HystrixTimeoutException) {
            return new GatewayClientResponse(HttpStatus.GATEWAY_TIMEOUT, DEFAULT_MESSAGE);
        } else {
            return new GatewayClientResponse(HttpStatus.INTERNAL_SERVER_ERROR, DEFAULT_MESSAGE);
        }
    }

}

As we can see, we’ve overridden the methods getRoute and fallbackResponse. The getRoute method returns the Id of the route for which we have to create the fallback. Whereas, the fallbackResponse method returns the custom fallback response, an object of type GatewayClientResponse in our case. The GatewayClientResponse is a simple implementation of ClientHttpResponse.

我们可以看到,我们已经重载了getRoutefallbackResponse方法。getRoute方法返回路由的Id,我们必须为其创建回退。而fallbackResponse方法返回自定义的回退响应,在我们的例子中是一个GatewayClientResponse类型的对象。GatewayClientResponseClientHttpResponse的一个简单实现。

3.2. Testing the Zuul Fallback

3.2.测试Zuul Fallback

Let’s now test the fallback we’ve created for weather service. Therefore, we’ll run the API Gateway application and make sure that the weather service application is stopped.

现在让我们测试一下我们为天气服务创建的回退。因此,我们将运行API网关应用程序,并确保天气服务应用程序被停止。

Now, let’s access the weather service API via the Zuul route and see the fallback response in action:

现在,让我们通过Zuul路由访问气象服务API,看看回退响应的作用。

$ curl -s localhost:7070/weather/today
Weather information is not available.

4. Fallback for All Routes

4.所有路线的回退

So far, we’ve seen how to create a fallback for a Zuul route using its route Id. However, let’s suppose, we also want to create a generic fallback for all other routes in our application. We can do so by creating one more implementation of FallbackProvider and returning * or null from the getRoute method, instead of the route Id:

到目前为止,我们已经看到了如何使用路由的Id为一个Zuul路由创建回退。然而,让我们假设,我们也想为我们的应用程序中的所有其他路由创建一个通用回退。我们可以通过再创建一个FallbackProvider的实现,并且getRoute方法返回*null,而不是路由Id

@Override
public String getRoute() {
    return "*"; // or return null;
}

5. Conclusion

5.总结

In this tutorial, we’ve seen an example of creating a fallback for a Zuul route. We’ve also seen how we can create a generic fallback for all Zuul routes.

在本教程中,我们看到了一个为一个Zuul路由创建回退的例子。我们还看到了如何为所有Zuul路由创建一个通用的回退。

As usual, the implementation of all these examples and code snippets can be found over on GitHub.

像往常一样,所有这些例子和代码片断的实现都可以在GitHub上找到over