Netflix Zuul

May 02 2017 SpringCloud

Routing and Filtering

本文将使用Netflix Zuul边缘服务库演示将请求路由和过滤到微服务应用程序的过程。

我们将会创建一个简单的微服务应用,然后使用Netflix Zuul创建一个反向代理应用来将请求转发到服务应用。您还将了解如何使用Zuul的过滤器功能。

创建一个微服务

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
package com.rason.book;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
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;

/**
* Created by rason on 5/2/17.
*/
@RestController
@SpringBootApplication
public class BookApplication {

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

@RequestMapping("/check-out")
public String checkOut() {
return "Spring boot in Action";
}

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

}

Book服务非常简单,就是一个REST控制器。为了不和反向代理应用端口冲突,我们配置一下Book服务的启动端口:

1
2
3
4
# application.yml

server:
port: 8090

创建反向代理服务

Spring Cloud Netflix 包含一个嵌入式的Zuul 代理,通过@EnableZuulProxy注解即可开启。这将使Gateway应用变成反向代理,将相关请求转发到其他服务(比如我们的Book服务)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
package com.rason.gateway;

import com.rason.gateway.filter.post.SimplePostFilter;
import com.rason.gateway.filter.pre.SimpleFilter;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.zuul.EnableZuulProxy;
import org.springframework.context.annotation.Bean;

/**
* Created by rason on 5/2/17.
*/
@EnableZuulProxy
@SpringBootApplication
public class GatewayApplication {

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

}

Zuul要转发来自Gateway的请求,则必须需要知道如何进行路由。所以我们需要通过zuul.routes属性来指定路由规则。

1
2
3
4
5
6
7
8
9
# application.yml

server:
port: 8087

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

上面的配置表明路径为/books的请求都将转发到http://localhost:8090应用上,也就是我们的Book服务。如果我们使用Eureka进行服务发现,也可以通过指定应用名字的方式进行转发。

测试

现在,我们同时启动两个应用,在浏览器中输入http://localhost:8087/books/available,会返回Spring in Action。这说明请求确实是通过网关应用转发到了Book服务。

添加过滤器

现在我们来看下如果通过我们的代理服务对请求进行过滤。Zuul有四种标准的过滤器类型:

我们来创建一个简单的前置过滤器:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
package com.rason.gateway.filter.pre;

import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.servlet.http.HttpServletRequest;

/**
* Created by rason on 5/2/17.
*/
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;
}
}

继承ZuulFilter类需要实现四个方法:

Zuul过滤器将请求和状态信息保存在RequestContext中。通过RequestContext我们可以获取到HttpServletRequest,然后将HTTP请求方法和URL在请求转发之前打印出来。

当然,我们需要在应用上下文中能找到这个过滤器才能进行过滤。所以,我们需要在应用启动的时候将其初始化,然后交给应用上下文管理,通过@Bean注解即可实现。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
package com.rason.gateway;

import com.rason.gateway.filter.post.SimplePostFilter;
import com.rason.gateway.filter.pre.SimpleFilter;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.zuul.EnableZuulProxy;
import org.springframework.context.annotation.Bean;

/**
* Created by rason on 5/2/17.
*/
@EnableZuulProxy
@SpringBootApplication
public class GatewayApplication {

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

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

}

测试

现在我们重启一下网关应用GatewayApplication。再次访问http://localhost:8087/books/available,会看到一下日志输出:

1
2017-05-02 16:56:31.505  INFO 12929 --- [nio-8087-exec-2] c.rason.gateway.filter.pre.SimpleFilter  : GET request to http://localhost:8087/books/available

总结

本文学习来使用Zuul创建一个简单的网关服务,可以对请求进行路由和过滤。

Zuul