Spring Cloud(六) Zuul

API网关服务 : Spring Cloud Zuul

  Spring Cloud Zuul通过与Spring Cloud Eureka进行整合,将自身注册为Eureka服务治理下的应用,同时从Eureka中获得所有其他微服务的实力信息,使得自动完成维护服务实例的工作。对于路由规则的维护,Zuul默认会通过服务名作为ContextPath的方式来创建路由映射。

  开发者可以通过使用Zuul来创建各种检校过滤器,然后指定那些规则的请求需要执行检校逻辑,只有通过检校的才会被路由到具体的微服务里接口,否则返回错误提示。

快速入门

构建网关

  1. 构建spring boot工程,引入依赖
    1
    2
    3
    4
    <dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-zuul</artifactId>
    </dependency>
  2. 创建启动类,添加EnableZuulProxy注解开启API网关服务功能
    1
    2
    3
    4
    5
    6
    7
    8
    @SpringCloudApplication
    @EnableZuulProxy
    public class ApigatewayApplication {

    public static void main(String[] args) {
    new SpringApplicationBuilder(ApigatewayApplication.class).web(true).run(args);
    }
    }
  3. 修改配置文件
    1
    2
    3
    4
    5
    server:
    port: 1501
    spring:
    application:
    name: api-gateway

请求路由

传统路由方式

/api-a-url/**的路由都会到http://localhost:8080/;如:访问http://localhost:1501/api-a-url/hello会到http://localhost:8080/hello

1
2
3
4
5
zuul:
routes:
api-a-url:
path: /api-a-url/**
url: http://localhost:8080/
面向服务的路由

  具体的路由由Eureka服务发现机制负责自动维护

  1. 添加Eureka的依赖
    1
    2
    3
    4
    <dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-eureka</artifactId>
    </dependency>
  2. 配置服务路由
    1
    2
    3
    4
    5
    6
    7
    8
    zuul:
    routes:
    api-b:
    path: /api-a/**
    serviceId: hello-service
    api-b:
    path: /api-b/**
    serviceId: feign-consurme

请求过滤

  继承ZuulFilter抽象类并实现定义的4个抽象函数就可以完成对请求的拦截和过滤。

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
42
43
44
45
46
47
@Log4j
public class RoleFilter extends ZuulFilter {
/**
* 过滤器类型,决定过滤器在请求的哪个周期中执行
* 定义为pre,在请求被路由之前执行
*/
@Override
public String filterType() {
return "pre";
}

/**
* 过滤器的执行顺序,当一个阶段中存在多个过滤器的时候,根据该方法返回值一次执行
*/
@Override
public int filterOrder() {
return 0;
}

/**
* 判断该过滤器是否需要执行。这里我们直接返回true,因此该过滤器对所有请求都生效。实际中利用该函数来指定过滤器的有效范围
*/
@Override
public boolean shouldFilter() {
return true;
}

/**
* 过滤器的具体逻辑
*/
@Override
public Object run() throws ZuulException {
RequestContext currentContext = RequestContext.getCurrentContext();
HttpServletRequest request = currentContext.getRequest();
log.info(String.format("send %s request to %s",request.getMethod(),request.getRequestURL().toString()));
String accessToken = request.getParameter("accessToken");
if (accessToken == null) {
log.warn("access token is empty");
currentContext.setSendZuulResponse(false); //设置不对其进行路由
currentContext.setResponseStatusCode(401); //设置错误返回码
currentContext.setResponseBody("没有access token"); //设置返回的body内容
return null;
}
log.info("access token ok");
return null;
}
}

  设置具体的配置类配置bean

1
2
3
4
5
6
7
8
@Configuration
public class FilterConfig {
@Bean
public RoleFilter roleFilter() {
return new RoleFilter();
}
}