路由与过滤

路由与过滤

路由与过滤

Routing and Filtering

通过此教程,你将使用Netflix Zuul边缘服务库来路由和过滤到一个微服务应用的请求。

This guide walks you through the process of routing and filtering requests to a microservice application using the Netflix Zuul edge service library.

将要做什么

What you’ll build

你将编写一个简单的微服务应用,并使用Netflix Zuul构建一个反向代理应用来转发请求到这个服务应用。以及如何使用Zuul通过代理服务来过滤请求。

You’ll write a simple microservice application and then build a reverse proxy application that uses Netflix Zuul to forward requests to the service application. You’ll also see how to use Zuul to filter requests made through the proxy service.

需要些什么

What you’ll need

如何完成此教程

How to complete this guide

与大多数Spring的入门教程相似,你可以从头开始并完成每一步,或者你也可以跳过你熟悉的设置步骤。无论怎样,你最终应当以有效代码结束。

Like most Spring Getting Started guides, you can start from scratch and complete each step, or you can bypass basic setup steps that are already familiar to you. Either way, you end up with working code.

如果从头开始,可参考使用Gradle构建

To start from scratch, move on to Build with Gradle.

如果要跳过基本步骤,按如下步骤:

To skip the basics, do the following:

  • 下载并解压此教程的源码仓库,或者使用Git进行clone:git clone https://github.com/spring-guides/gs-routing-and-filtering.git
  • 进入gs-routing-and-filtering/initial目录
  • 跳至构建一个微服务.
  • Download and unzip the source repository for this guide, or clone it using Git: git clone https://github.com/spring-guides/gs-routing-and-filtering.git
  • cd into gs-routing-and-filtering/initial
  • Jump ahead to Set up a microservice.

当你完成时,你可以与gs-routing-and-filtering/complete中的代码对比检查。

When you’re finished, you can check your results against the code in gs-routing-and-filtering/complete.

构建一个微服务

Set up a microservice

这个Book服务非常简单。如下修改BookApplication.java

The Book service will be super-simple. Edit BookApplication.java to look like this:

book/src/main/java/hello/BookApplication.java

package hello;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@SpringBootApplication
public class BookApplication {

  @RequestMapping(value = "/available")
  public String available() {
    return "Spring in Action";
  }

  @RequestMapping(value = "/checked-out")
  public String checkedOut() {
    return "Spring Boot in Action";
  }

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

BookApplication类是一个REST控制类,@RestController将此类标记为一个控制器类,并保证此类中@RequestMapping方法的返回值会自动转换并直接写入HTTP响应中。

The BookApplication class is now a REST controller. @RestController marks the class as a controller class, and also ensures that return values from @RequestMapping methods in this class will be automatically converted appropriately and written directly to the HTTP response.

说到@RequestMapping方法,我们增加了两个available()checkedOut()。分别处理/available/checked-out路径的请求,并返回一本书的名称String字符串。

Speaking of @RequestMapping methods, we’ve added two: available() and checkedOut(). They handle requests to the paths /available and /checked-out, each simply returning the String name of a book.

src/main/resources/application.properties中设置应用名称book

Set the application name (book) in src/main/resources/application.properties.

book/src/main/resources/application.properties

spring.application.name=book

server.port=8090

还需要设置server.port,以防止都在本地运行时,与边缘服务的端口冲突。

We’re also setting server.port here so that it won’t conflict with our edge service when we get both services up and running locally.

创建一个边缘服务

Create an edge service

Spring Cloud Netflix包含了内嵌的Zuul代理,可通过@EnableZuulProxy注解启用。这样做会将网关服务转变为一个反向代理,转发到其他服务的相关调用,例如此例的Book服务。

Spring Cloud Netflix includes an embedded Zuul proxy, which we can enable with the @EnableZuulProxy annotation. This will turn the Gateway application into a reverse proxy that forwards relevant calls to other services—such as our Book service.

打开网关应用的GatewayApplication类并添加注解,如下:

Open the Gateway application’s GatewayApplication class and add the annotation, like so:

gateway/src/main/java/hello/GatewayApplication.java

package hello;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.zuul.EnableZuulProxy;

@EnableZuulProxy
@SpringBootApplication
public class GatewayApplication {

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

}

为了从Gateway应用中转发请求,我们需要告诉Zuul,应该观察哪个路由以及根据路由转发到请求到哪个服务。我们用zuul.routes中的属性来指定路由。我们所有微服务的每一个服务都可以有一个入口如zuul.routes.NAME,其中NAME是应用名(即spring.application.name属性对应值)。

To forward requests from the Gateway application, we need to tell Zuul the routes that it should watch and the services to which to forward requests to those routes. We specify routes using properties under zuul.routes. Each of our microservices can have an entry under zuul.routes.NAME, where NAME is the application name (as stored in the spring.application.name property).

在Gateway应用的src/main/resources路径下新建application.properties文件。如下:

Add the application.properties file to a new directory, src/main/resources, in the Gateway application. It should look like this:

gateway/src/main/resources/application.properties

zuul.routes.books.url=http://localhost:8090

ribbon.eureka.enabled=false

server.port=8080

Spring Cloud Zuul将根据应用名称自动设置路径。例如我们设置了zuul.routes.books.url,Zuul将自动代理/books的请求到此URL上。

Spring Cloud Zuul will automatically set the path to the application name. In this sample because we set zuul.routes.books.url, so Zuul will proxy requests to /books to this URL.

注意倒数第二个属性:Spring Cloud Netflix Zuul使用了Netflix的Ribbon来执行客户端的负载均衡,默认Ribbon将使用Netflix Eureka做服务发现。在此例中,我们省掉了服务发现,所以设置ribbon.eureka.enabledfalse。因为Ribbon无法使用Eureka查找服务,我们必须为Book服务指定一个url

Notice the second-to-last property in our file: Spring Cloud Netflix Zuul uses Netflix’s Ribbon to perform client-side load balancing, and by default, Ribbon would use Netflix Eureka for service discovery. For this simple example, we’re skipping service discovery, so we’ve set ribbon.eureka.enabled to false. Since Ribbon now can’t use Eureka to look up services, we must specify a url for the Book service.

添加一个过滤器

Add a filter

现在我们看看如何通过代理服务来过滤请求。Zuul有四种标准的过滤类型:

Now let’s see how we can filter requests through our proxy service. Zuul has four standard filter types:

  • pre过滤器在请求被路由前执行,
  • route过滤器是正在路由此请求的时候被处理,
  • post过滤器在请求被路由后执行,
  • error过滤器是在处理请求时发生错误时被执行。
  • pre filters are executed before the request is routed,
  • route filters can handle the actual routing of the request,
  • post filters are executed after the request has been routed, and
  • error filters execute if an error occurs in the course of handling the request.

我们将写一个pre过滤器。任何继承了com.netflix.zuul.ZuulFilter@Bean都会被Spring Cloud Netflix识别为一个过滤器,且在应用上下文中可用。新建一个文件夹src/main/java/hello/filters/pre,在其中创建过滤器文件SimpleFilter.java

We’re going to write a pre filter. Spring Cloud Netflix picks up, as a filter, any @Bean which extends com.netflix.zuul.ZuulFilter and is available in the application context. Create a new directory, src/main/java/hello/filters/pre, and within it, create the filter file, SimpleFilter.java:

`gateway/src/main/java/hello/filters/pre/SimpleFilter.java

package hello.filters.pre;

import javax.servlet.http.HttpServletRequest;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.ZuulFilter;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class SimpleFilter extends ZuulFilter {

  private static Logger log = LoggerFactory.getLogger(SimpleFilter.class);

  @Override
  public String filterType() {
    return "pre";
  }

  @Override
  public int filterOrder() {
    return 1;
  }

  @Override
  public boolean shouldFilter() {
    return true;
  }

  @Override
  public Object run() {
    RequestContext ctx = RequestContext.getCurrentContext();
    HttpServletRequest request = ctx.getRequest();

    log.info(String.format("%s request to %s", request.getMethod(), request.getRequestURL().toString()));

    return null;
  }

}

Filter类实现了四个方法:

Filter classes implement four methods:

  • filterType()返回一个表示过滤器类型的字符串String,在此例中是pre,或者对于路由过滤器来说则返回route
  • filterOrder()表示过滤器相对于其他过滤器被执行的顺序。
  • shouldFilter()包含决定此过滤器是否被执行的逻辑(此例中过滤器总会被执行)。
  • run()包含过滤器的功能。
  • filterType() returns a String that stands for the type of the filter—in this case, pre, or it could be route for a routing filter.
  • filterOrder() gives the order in which this filter will be executed, relative to other filters.
  • shouldFilter() contains the logic that determines when to execute this filter (this particular filter will always be executed).
  • run() contains the functionality of the filter.

Zuul过滤器在RequestContext中存储请求与状态信息(并使用其来共享)。我们使用它来获取HttpServletRequest,然后在发送之前记录请求的HTTP方法和URL。

Zuul filters store request and state information in (and share it by means of) the RequestContext. We’re using that to get at the HttpServletRequest, and then we log the HTTP method and URL of the request before it is sent on its way.

GatewayApplication类有一个注解@SpringBootApplication,等同于有一个@Configuration注解,告诉Spring寻找指定有@Bean定义的类。在这里增加一个SimpleFilter

The GatewayApplication class is annotated with @SpringBootApplication, which is equivalent to (among others) the @Configuration annotation that tells Spring to look in a given class for @Bean definitions. Add one for our SimpleFilter here:

gateway/src/main/java/hello/GatewayApplication.java

package hello;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.zuul.EnableZuulProxy;
import org.springframework.context.annotation.Bean;
import hello.filters.pre.SimpleFilter;

@EnableZuulProxy
@SpringBootApplication
public class GatewayApplication {

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

  @Bean
  public SimpleFilter simpleFilter() {
    return new SimpleFilter();
  }

}

试一试

Trying it out

首先确保两个应用都已经运行。在浏览器中通过Gateway应用访问Book应用的一个端点。如果你使用了此教程中的配置,则可直接通过localhost:8090访问,或者通过Gateway服务的localhost:8080/books来访问Book服务。

Make sure that both applications are running. In a browser, visit one of the Book application’s endpoints via the Gateway application. If you’ve used the configuration shown in this guide, you can access the Book service directly at localhost:8090 and via the Gateway service at localhost:8080/books.

访问Book服务端点的其中一个,如localhost:8080/books/available,你可以看见处理Book应用之前,在Gateway应用中记录了请求的方法:

Visit one of the Book service endpoints, as localhost:8080/books/available, and you should see your request’s method logged by the Gateway application before it’s handed on to the Book application:

2016-01-19 16:51:14.672  INFO 58807 --- [nio-8080-exec-6] hello.filters.pre.SimpleFilter           : GET request to http://localhost:8080/books/available
2016-01-19 16:51:14.672  INFO 58807 --- [nio-8080-exec-6] o.s.c.n.zuul.filters.ProxyRouteLocator   : Finding route for path: /books/available

总结

Summary

恭喜!你已经完成了使用Spring来开发一个边缘服务,来代理并过滤微服务中的请求。

Congratulations! You’ve just used Spring to develop an edge service application that can proxy and filter requests for your microservices.

翻译部分版权归YahaCode团队所有。仅供学习研究之用,任何组织或个人不得私自以此用于任何形式的商业目的

发表评论